├── .all-contributorsrc
├── .changeset
├── README.md
└── config.json
├── .codesandbox
└── tasks.json
├── .cspell.json
├── .cursor
└── rules
│ └── react-hook-yolo.mdc
├── .eslintignore
├── .eslintrc.js
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── actions
│ └── ci-setup
│ │ └── action.yml
├── assets
│ ├── Final_Copy_8.png
│ ├── Final_Icon.svg
│ ├── Look.png
│ ├── favicon-24x24.png
│ ├── favicon-24x24.svg
│ ├── favicon-32x32.png
│ ├── favicon-32x32.svg
│ ├── favicon-48x48.png
│ ├── favicon-48x48.svg
│ ├── icon.png
│ ├── icon.svg
│ ├── logo-dark.png
│ ├── logo-light.png
│ ├── rooks.png
│ └── rooks.svg
├── powered-by-vercel.svg
├── stale.yml
└── workflows
│ ├── ci-release.yml
│ ├── contributors.yml
│ └── pr.yml
├── .gitignore
├── .husky
├── _
│ └── husky.sh
└── pre-commit
├── .mergify.yml
├── .nvmrc
├── .prettierignore
├── .prettierrc.json
├── .vscode
└── settings.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── MAINTENANCE.md
├── README.md
├── apps
└── website
│ ├── CHANGELOG.md
│ ├── content-collections.ts
│ ├── content
│ └── docs
│ │ ├── hooks
│ │ ├── meta.json
│ │ ├── useArrayState.mdx
│ │ ├── useAsyncEffect.mdx
│ │ ├── useAudio.mdx
│ │ ├── useBoundingclientrect.mdx
│ │ ├── useBoundingclientrectRef.mdx
│ │ ├── useCountdown.mdx
│ │ ├── useCounter.mdx
│ │ ├── useDebounce.mdx
│ │ ├── useDebounceFn.mdx
│ │ ├── useDebouncedValue.mdx
│ │ ├── useDeepCompareEffect.mdx
│ │ ├── useDidMount.mdx
│ │ ├── useDidUpdate.mdx
│ │ ├── useDimensionsRef.mdx
│ │ ├── useDocumentEventListener.mdx
│ │ ├── useDocumentTitle.mdx
│ │ ├── useDocumentVisibilityState.mdx
│ │ ├── useEffectOnceWhen.mdx
│ │ ├── useEventListenerRef.mdx
│ │ ├── useFileDropRef.mdx
│ │ ├── useFocus.mdx
│ │ ├── useFocusWithin.mdx
│ │ ├── useForkRef.mdx
│ │ ├── useFreshCallback.mdx
│ │ ├── useFreshRef.mdx
│ │ ├── useFreshTick.mdx
│ │ ├── useFullscreen.mdx
│ │ ├── useGeolocation.mdx
│ │ ├── useGetIsMounted.mdx
│ │ ├── useInViewRef.mdx
│ │ ├── useInput.mdx
│ │ ├── useIntersectionObserverRef.mdx
│ │ ├── useIntervalWhen.mdx
│ │ ├── useIsDroppingFiles.mdx
│ │ ├── useIsomorphicEffect.mdx
│ │ ├── useKey.mdx
│ │ ├── useKeyBindings.mdx
│ │ ├── useKeyRef.mdx
│ │ ├── useKeys.mdx
│ │ ├── useLifecycleLogger.mdx
│ │ ├── useLocalstorageState.mdx
│ │ ├── useLockBodyScroll.mdx
│ │ ├── useMapState.mdx
│ │ ├── useMediaMatch.mdx
│ │ ├── useMergeRefs.mdx
│ │ ├── useMouse.mdx
│ │ ├── useMouseMoveDelta.mdx
│ │ ├── useMouseWheelDelta.mdx
│ │ ├── useMultiSelectableList.mdx
│ │ ├── useMutationObserver.mdx
│ │ ├── useMutationObserverRef.mdx
│ │ ├── useNativeMapState.mdx
│ │ ├── useNavigatorLanguage.mdx
│ │ ├── useOnClickRef.mdx
│ │ ├── useOnHoverRef.mdx
│ │ ├── useOnLongHover.mdx
│ │ ├── useOnLongPress.mdx
│ │ ├── useOnWindowResize.mdx
│ │ ├── useOnWindowScroll.mdx
│ │ ├── useOnline.mdx
│ │ ├── useOrientation.mdx
│ │ ├── useOutsideClick.mdx
│ │ ├── useOutsideClickRef.mdx
│ │ ├── usePreviousDifferent.mdx
│ │ ├── usePreviousImmediate.mdx
│ │ ├── usePromise.mdx
│ │ ├── useQueueState.mdx
│ │ ├── useRaf.mdx
│ │ ├── useRefElement.mdx
│ │ ├── useRenderCount.mdx
│ │ ├── useResizeObserverRef.mdx
│ │ ├── useSafeSetState.mdx
│ │ ├── useSelect.mdx
│ │ ├── useSelectableList.mdx
│ │ ├── useSessionstorageState.mdx
│ │ ├── useSetState.mdx
│ │ ├── useSpeech.mdx
│ │ ├── useStackState.mdx
│ │ ├── useThrottle.mdx
│ │ ├── useTimeTravelState.mdx
│ │ ├── useTimeoutWhen.mdx
│ │ ├── useToggle.mdx
│ │ ├── useUndoRedoState.mdx
│ │ ├── useUndoState.mdx
│ │ ├── useVibrate.mdx
│ │ ├── useVideo.mdx
│ │ ├── useWhyDidYouUpdate.mdx
│ │ ├── useWillUnmount.mdx
│ │ ├── useWindowEventListener.mdx
│ │ ├── useWindowScrollPosition.mdx
│ │ └── useWindowSize.mdx
│ │ └── index.mdx
│ ├── dump-contributors.ts
│ ├── eslint.config.js
│ ├── next.config.ts
│ ├── package.json
│ ├── postcss.config.mjs
│ ├── public
│ └── images
│ │ └── powered-by-vercel.svg
│ ├── source.ts
│ ├── src
│ ├── app
│ │ ├── api
│ │ │ └── search
│ │ │ │ └── route.tsx
│ │ ├── docs
│ │ │ ├── [[...slug]]
│ │ │ │ └── page.tsx
│ │ │ ├── docs.css
│ │ │ └── layout.tsx
│ │ ├── globals.css
│ │ ├── layout.config.tsx
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── components
│ │ ├── CONTRIBUTORS.md
│ │ ├── ClientHighlight.tsx
│ │ ├── ClientHightlightWrapper.tsx
│ │ ├── ContributorList.tsx
│ │ ├── Contributors.tsx
│ │ └── contributors-list-data.ts
│ ├── pages
│ │ ├── _app.tsx.old
│ │ ├── _document.tsx.old
│ │ ├── docs
│ │ │ └── [slug].tsx.old
│ │ ├── getting-started.md
│ │ ├── home-sandbox.md
│ │ ├── index.tsx.old
│ │ ├── list-of-hooks.md
│ │ └── motivation.md
│ ├── providers
│ │ └── QueryProvider.tsx
│ └── utils
│ │ ├── mdxSerialize.ts
│ │ └── url.ts
│ └── tsconfig.json
├── data
├── docs
│ ├── rooks.md
│ ├── useArrayState.md
│ ├── useAsyncEffect.md
│ ├── useAudio.md
│ ├── useBoundingclientrect.md
│ ├── useBoundingclientrectRef.md
│ ├── useCountdown.md
│ ├── useCounter.md
│ ├── useDebounce.md
│ ├── useDebounceFn.md
│ ├── useDebouncedValue.md
│ ├── useDeepCompareEffect.md
│ ├── useDidMount.md
│ ├── useDidUpdate.md
│ ├── useDimensionsRef.md
│ ├── useDocumentEventListener.md
│ ├── useDocumentTitle.md
│ ├── useDocumentVisibilityState.md
│ ├── useEffectOnceWhen.md
│ ├── useEventListenerRef.md
│ ├── useFileDropRef.md
│ ├── useFocus.md
│ ├── useFocusWithin.md
│ ├── useForkRef.md
│ ├── useFreshCallback.md
│ ├── useFreshRef.md
│ ├── useFreshTick.md
│ ├── useFullscreen.md
│ ├── useGeolocation.md
│ ├── useGetIsMounted.md
│ ├── useInViewRef.md
│ ├── useInput.md
│ ├── useIntersectionObserverRef.md
│ ├── useIntervalWhen.md
│ ├── useIsDroppingFiles.md
│ ├── useIsomorphicEffect.md
│ ├── useKey.md
│ ├── useKeyBindings.md
│ ├── useKeyRef.md
│ ├── useKeys.md
│ ├── useLifecycleLogger.md
│ ├── useLocalstorageState.md
│ ├── useLockBodyScroll.md
│ ├── useMapState.md
│ ├── useMediaMatch.md
│ ├── useMergeRefs.md
│ ├── useMouse.md
│ ├── useMouseMoveDelta.md
│ ├── useMouseWheelDelta.md
│ ├── useMultiSelectableList.md
│ ├── useMutationObserver.md
│ ├── useMutationObserverRef.md
│ ├── useNativeMapState.md
│ ├── useNavigatorLanguage.md
│ ├── useOnClickRef.md
│ ├── useOnHoverRef.md
│ ├── useOnLongHover.md
│ ├── useOnLongPress.md
│ ├── useOnWindowResize.md
│ ├── useOnWindowScroll.md
│ ├── useOnline.md
│ ├── useOrientation.md
│ ├── useOutsideClick.md
│ ├── useOutsideClickRef.md
│ ├── usePreviousDifferent.md
│ ├── usePreviousImmediate.md
│ ├── usePromise.md
│ ├── useQueueState.md
│ ├── useRaf.md
│ ├── useRefElement.md
│ ├── useRenderCount.md
│ ├── useResizeObserverRef.md
│ ├── useSafeSetState.md
│ ├── useSelect.md
│ ├── useSelectableList.md
│ ├── useSessionstorageState.md
│ ├── useSetState.md
│ ├── useSpeech.md
│ ├── useStackState.md
│ ├── useThrottle.md
│ ├── useTimeTravelState.md
│ ├── useTimeoutWhen.md
│ ├── useToggle.md
│ ├── useUndoRedoState.md
│ ├── useUndoState.md
│ ├── useVibrate.md
│ ├── useVideo.md
│ ├── useWhyDidYouUpdate.md
│ ├── useWillUnmount.md
│ ├── useWindowEventListener.md
│ ├── useWindowScrollPosition.md
│ └── useWindowSize.md
└── hooks-list.json
├── i18n
└── en.json
├── package.json
├── packages
├── eslint-config
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── base.js
│ ├── next.js
│ ├── package.json
│ └── react-internal.js
├── rooks
│ ├── .escheckrc
│ ├── .gitignore
│ ├── .npmignore
│ ├── .size-limit.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── build.js
│ ├── esbuild.mjs
│ ├── eslint.config.mjs
│ ├── jest.config.ts
│ ├── package.json
│ ├── src
│ │ ├── __tests__
│ │ │ ├── ErrorBoundary.tsx
│ │ │ ├── shared.spec.ts
│ │ │ ├── useArrayState.spec.ts
│ │ │ ├── useAsyncEffect.spec.ts
│ │ │ ├── useAudio.spec.tsx
│ │ │ ├── useCountdown.spec.tsx
│ │ │ ├── useCounter.spec.tsx
│ │ │ ├── useDebounce.spec.tsx
│ │ │ ├── useDebounceFn.spec.ts
│ │ │ ├── useDebouncedValue.spec.ts
│ │ │ ├── useDeepCompareEffect.spec.ts
│ │ │ ├── useDidMount.spec.ts
│ │ │ ├── useDidUpdate.spec.tsx
│ │ │ ├── useDimensionsRef.spec.tsx
│ │ │ ├── useDocumentEventListener.spec.tsx
│ │ │ ├── useDocumentTitle.spec.ts
│ │ │ ├── useDocumentVisibilityState.spec.ts
│ │ │ ├── useEffectOnceWhen.spec.tsx
│ │ │ ├── useEventListenerRef.spec.tsx
│ │ │ ├── useFileDropRef.spec.tsx
│ │ │ ├── useFocus.spec.tsx
│ │ │ ├── useFocusWithin.spec.tsx
│ │ │ ├── useForkRef.spec.tsx
│ │ │ ├── useFreshCallback.spec.ts
│ │ │ ├── useFreshRef.spec.tsx
│ │ │ ├── useFreshTick.spec.tsx
│ │ │ ├── useGeolocation.spec.tsx
│ │ │ ├── useGetIsMounted.spec.ts
│ │ │ ├── useInViewRef.spec.tsx
│ │ │ ├── useInput.spec.tsx
│ │ │ ├── useIntervalWhen.spec.tsx
│ │ │ ├── useIsDroppingFiles.spec.tsx
│ │ │ ├── useKey.spec.tsx
│ │ │ ├── useKeyBindings.spec.tsx
│ │ │ ├── useKeyRef.spec.tsx
│ │ │ ├── useKeys.spec.tsx
│ │ │ ├── useLifecycleLogger.spec.ts
│ │ │ ├── useLocalstorageState.spec.tsx
│ │ │ ├── useLockBodyScroll.spec.tsx
│ │ │ ├── useMapState.spec.tsx
│ │ │ ├── useMediaMatch.spec.tsx
│ │ │ ├── useMouse.spec.tsx
│ │ │ ├── useMouseMoveDelta.spec.tsx
│ │ │ ├── useMouseWheelDelta.spec.tsx
│ │ │ ├── useMutationObserver.spec.tsx
│ │ │ ├── useMutilSelectableList.spec.ts
│ │ │ ├── useNativeMapState.spec.ts
│ │ │ ├── useNavigatorLanguage.spec.tsx
│ │ │ ├── useOnClickRef.spec.tsx
│ │ │ ├── useOnHoverRef.spec.tsx
│ │ │ ├── useOnLongHover.spec.tsx
│ │ │ ├── useOnLongPress.spec.tsx
│ │ │ ├── useOnWindowResize.spec.ts
│ │ │ ├── useOnWindowScroll.spec.ts
│ │ │ ├── useOnline.spec.tsx
│ │ │ ├── useOrientation.spec.tsx
│ │ │ ├── useOutsideClick.spec.tsx
│ │ │ ├── useOutsideClickRef.spec.tsx
│ │ │ ├── usePreviousDifferent.spec.ts
│ │ │ ├── usePreviousImmediate.spec.ts
│ │ │ ├── usePromise.spec.ts
│ │ │ ├── useQueueState.spec.ts
│ │ │ ├── useRaf.spec.tsx
│ │ │ ├── useRenderCount.spec.ts
│ │ │ ├── useResizeObserver.spec.tsx
│ │ │ ├── useSafeSetState.spec.ts
│ │ │ ├── useSelctableList.spec.ts
│ │ │ ├── useSelect.spec.ts
│ │ │ ├── useSessionstorageState.spec.tsx
│ │ │ ├── useSetState.spec.ts
│ │ │ ├── useSpeech.spec.ts
│ │ │ ├── useStackState.spec.ts
│ │ │ ├── useThrottle.spec.tsx
│ │ │ ├── useTimeTravelState.spec.ts
│ │ │ ├── useTimeoutWhen.spec.ts
│ │ │ ├── useToggle.spec.tsx
│ │ │ ├── useUndoRedoState.spec.ts
│ │ │ ├── useUndoState.spec.tsx
│ │ │ ├── useVibrate.spec.ts
│ │ │ ├── useVideo.spec.tsx
│ │ │ ├── useWarningOnMountInDevelopment.spec.ts
│ │ │ ├── useWhyDidYouUpdate.spec.tsx
│ │ │ ├── useWillUnmount.spec.tsx
│ │ │ ├── useWindowEventListener.spec.tsx
│ │ │ ├── useWindowScrollPosition.spec.ts
│ │ │ └── useWindowSize.spec.tsx
│ │ ├── hooks
│ │ │ ├── useArrayState.ts
│ │ │ ├── useAsyncEffect.ts
│ │ │ ├── useAudio.ts
│ │ │ ├── useBoundingclientrect.ts
│ │ │ ├── useBoundingclientrectRef.ts
│ │ │ ├── useCountdown.ts
│ │ │ ├── useCounter.ts
│ │ │ ├── useDebounce.ts
│ │ │ ├── useDebounceFn.ts
│ │ │ ├── useDebouncedValue.ts
│ │ │ ├── useDeepCompareEffect.ts
│ │ │ ├── useDidMount.ts
│ │ │ ├── useDidUpdate.ts
│ │ │ ├── useDimensionsRef.ts
│ │ │ ├── useDocumentEventListener.ts
│ │ │ ├── useDocumentTitle.ts
│ │ │ ├── useDocumentVisibilityState.ts
│ │ │ ├── useEffectOnceWhen.ts
│ │ │ ├── useEventListenerRef.ts
│ │ │ ├── useFileDropRef.ts
│ │ │ ├── useFocus.ts
│ │ │ ├── useFocusWithin.ts
│ │ │ ├── useForkRef.ts
│ │ │ ├── useFreshCallback.ts
│ │ │ ├── useFreshRef.ts
│ │ │ ├── useFreshTick.ts
│ │ │ ├── useFullscreen.ts
│ │ │ ├── useGeolocation.ts
│ │ │ ├── useGetIsMounted.ts
│ │ │ ├── useGlobalObjectEventListener.ts
│ │ │ ├── useInViewRef.ts
│ │ │ ├── useInput.ts
│ │ │ ├── useIntersectionObserverRef.ts
│ │ │ ├── useIntervalWhen.ts
│ │ │ ├── useIsDroppingFiles.ts
│ │ │ ├── useIsomorphicEffect.ts
│ │ │ ├── useKey.ts
│ │ │ ├── useKeyBindings.ts
│ │ │ ├── useKeyRef.ts
│ │ │ ├── useKeys.ts
│ │ │ ├── useLifecycleLogger.ts
│ │ │ ├── useLocalstorageState.ts
│ │ │ ├── useLockBodyScroll.ts
│ │ │ ├── useMapState.ts
│ │ │ ├── useMediaMatch.ts
│ │ │ ├── useMergeRefs.ts
│ │ │ ├── useMouse.ts
│ │ │ ├── useMouseMoveDelta.ts
│ │ │ ├── useMouseWheelDelta.ts
│ │ │ ├── useMultiSelectableList.ts
│ │ │ ├── useMutationObserver.ts
│ │ │ ├── useMutationObserverRef.ts
│ │ │ ├── useNativeMapState.ts
│ │ │ ├── useNavigatorLanguage.ts
│ │ │ ├── useOnClickRef.ts
│ │ │ ├── useOnHoverRef.ts
│ │ │ ├── useOnLongHover.ts
│ │ │ ├── useOnLongPress.ts
│ │ │ ├── useOnWindowResize.ts
│ │ │ ├── useOnWindowScroll.ts
│ │ │ ├── useOnline.ts
│ │ │ ├── useOrientation.ts
│ │ │ ├── useOutsideClick.ts
│ │ │ ├── useOutsideClickRef.ts
│ │ │ ├── usePreviousDifferent.ts
│ │ │ ├── usePreviousImmediate.ts
│ │ │ ├── usePromise.ts
│ │ │ ├── useQueueState.ts
│ │ │ ├── useRaf.ts
│ │ │ ├── useRefElement.ts
│ │ │ ├── useRenderCount.ts
│ │ │ ├── useResizeObserverRef.ts
│ │ │ ├── useSafeSetState.ts
│ │ │ ├── useSelect.ts
│ │ │ ├── useSelectableList.ts
│ │ │ ├── useSessionstorageState.ts
│ │ │ ├── useSetState.ts
│ │ │ ├── useSpeech.ts
│ │ │ ├── useStackState.ts
│ │ │ ├── useThrottle.ts
│ │ │ ├── useTimeTravelState.ts
│ │ │ ├── useTimeoutWhen.ts
│ │ │ ├── useToggle.ts
│ │ │ ├── useUndoRedoState.ts
│ │ │ ├── useUndoState.ts
│ │ │ ├── useVibrate.ts
│ │ │ ├── useVideo.ts
│ │ │ ├── useWarningOnMountInDevelopment.ts
│ │ │ ├── useWhyDidYouUpdate.ts
│ │ │ ├── useWillUnmount.ts
│ │ │ ├── useWindowEventListener.ts
│ │ │ ├── useWindowScrollPosition.ts
│ │ │ ├── useWindowSize.ts
│ │ │ └── warning.ts
│ │ ├── index-standalone.ts
│ │ ├── index.ts
│ │ ├── jest.setup.ts
│ │ ├── types
│ │ │ ├── index-value.ts
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ └── utils
│ │ │ ├── doesIdentifierMatchKeyboardEvent.ts
│ │ │ ├── domrect-polyfill.ts
│ │ │ ├── noop.ts
│ │ │ └── utils.ts
│ ├── tsconfig.build.json
│ ├── tsconfig.e2e.json
│ └── tsconfig.json
└── typescript-config
│ ├── CHANGELOG.md
│ ├── base.json
│ ├── nextjs.json
│ ├── package.json
│ └── react-library.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── prettier.config.cjs
├── scripts
├── .eslintrc
├── bump-peer-dep-ranges.js
├── create
│ ├── addHookToListAndUpdate.mjs
│ └── index.mjs
├── docs
│ ├── index.ts
│ ├── parse-readme.ts
│ ├── remove-top-heading.ts
│ └── transform-headings.ts
├── update-all-contributors
│ └── index.mjs
└── update-package-list-to-markdown
│ └── index.mjs
├── static
├── css
│ └── custom.css
└── img
│ ├── favicon.ico
│ ├── oss_logo.png
│ ├── rooks-logo.png
│ ├── undraw_code_review.svg
│ ├── undraw_monitor.svg
│ ├── undraw_note_list.svg
│ ├── undraw_online.svg
│ ├── undraw_open_source.svg
│ ├── undraw_operating_system.svg
│ ├── undraw_react.svg
│ ├── undraw_tweetstorm.svg
│ └── undraw_youtube_tutorial.svg
├── template
├── Examples.md
├── README.md
├── index.spec.template
├── index.template
├── shared.template
└── title-card.svg
└── turbo.json
/.changeset/README.md:
--------------------------------------------------------------------------------
1 | # Changesets
2 |
3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4 | with multi-package repos, or single-package repos to help you version and publish your code. You can
5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6 |
7 | We have a quick list of common questions to get you started engaging with this project in
8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
9 |
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@2.1.0/schema.json",
3 | "changelog": [
4 | "@changesets/changelog-github",
5 | { "repo": "imbhargav5/rooks" }
6 | ],
7 | "commit": false,
8 | "fixed": [],
9 | "linked": [],
10 | "access": "restricted",
11 | "baseBranch": "main",
12 | "updateInternalDependencies": "patch",
13 | "ignore": []
14 | }
15 |
--------------------------------------------------------------------------------
/.codesandbox/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // These tasks will run in order when initializing your CodeSandbox project.
3 | "setupTasks": [
4 | {
5 | "name": "Install Dependencies",
6 | "command": "yarn install"
7 | }
8 | ],
9 |
10 | // These tasks can be run from CodeSandbox. Running one will open a log in the app.
11 | "tasks": {
12 | "build": {
13 | "name": "build",
14 | "command": "yarn build",
15 | "runAtStart": false
16 | },
17 | "dev": {
18 | "name": "dev",
19 | "command": "yarn dev",
20 | "runAtStart": true
21 | },
22 | "lint": {
23 | "name": "lint",
24 | "command": "yarn lint",
25 | "runAtStart": false
26 | },
27 | "clean": {
28 | "name": "clean",
29 | "command": "yarn clean",
30 | "runAtStart": false
31 | },
32 | "format": {
33 | "name": "format",
34 | "command": "yarn format",
35 | "runAtStart": false
36 | },
37 | "test": {
38 | "name": "test",
39 | "command": "yarn test",
40 | "runAtStart": false
41 | },
42 | "start": {
43 | "name": "start",
44 | "command": "yarn start",
45 | "runAtStart": false
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/.cspell.json:
--------------------------------------------------------------------------------
1 | {
2 | "allowCompoundWords": true,
3 | "ignoreRegExpList": ["/.*[0-9].*/"],
4 | "language": "en",
5 | "minWordLength": 5,
6 | "version": "0.2",
7 | "words": [
8 | "Codecov",
9 | "contributorsrc",
10 | "data-testid",
11 | "imbhargav5",
12 | "jsdelivr",
13 | "jsvalue",
14 | "localstorage",
15 | "Mdast",
16 | "nextui",
17 | "nocheck",
18 | "tsconfigs",
19 | "tspaths",
20 | "unoptimized",
21 | "updation"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | *.d.ts
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | // This tells ESLint to load the config from the package `eslint-config-custom`
4 | extends: ["custom"],
5 | settings: {
6 | next: {
7 | rootDir: ["apps/*/"],
8 | },
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | name: Bug report
4 | about: Create a report to help us improve
5 | ---**Describe the bug**
6 | A clear and concise description of what the bug is.
7 |
8 | **To Reproduce**
9 | Steps to reproduce the behavior:
10 |
11 | 1. Go to '...'
12 | 2. Click on '....'
13 | 3. Scroll down to '....'
14 | 4. See error
15 |
16 | **Expected behavior**
17 | A clear and concise description of what you expected to happen.
18 |
19 | **Screenshots**
20 | If applicable, add screenshots to help explain your problem.
21 |
22 | **Desktop (please complete the following information):**
23 |
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **Smartphone (please complete the following information):**
29 |
30 | - Device: [e.g. iPhone6]
31 | - OS: [e.g. iOS8.1]
32 | - Browser [e.g. stock browser, safari]
33 | - Version [e.g. 22]
34 |
35 | **Additional context**
36 | Add any other context about the problem here.
37 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | name: Feature request
4 | about: Suggest an idea for this project
5 | ---**Is your feature request related to a problem? Please describe.**
6 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
7 |
8 | **Describe the solution you'd like**
9 | A clear and concise description of what you want to happen.
10 |
11 | **Describe alternatives you've considered**
12 | A clear and concise description of any alternative solutions or features you've considered.
13 |
14 | **Additional context**
15 | Add any other context or screenshots about the feature request here.
16 |
--------------------------------------------------------------------------------
/.github/actions/ci-setup/action.yml:
--------------------------------------------------------------------------------
1 | name: "CI setup"
2 | description: "Sets up Node.js, pnpm, and caches dependencies"
3 | runs:
4 | using: "composite"
5 | steps:
6 | - name: Use Node.js 22.x
7 | uses: actions/setup-node@v4
8 | with:
9 | node-version: 22.x
10 | - name: Setup pnpm
11 | uses: pnpm/action-setup@v4
12 | - name: Get pnpm store directory
13 | id: pnpm-cache
14 | run: |
15 | echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
16 | shell: bash
17 | - uses: actions/cache@v4
18 | id: pnpm-cache-hit
19 | with:
20 | path: |
21 | ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
22 | node_modules
23 | */*/node_modules
24 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
25 | - name: Install project dependencies
26 | if: steps.pnpm-cache-hit.outputs.cache-hit != 'true'
27 | run: pnpm install
28 | shell: bash
29 |
--------------------------------------------------------------------------------
/.github/assets/Final_Copy_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/Final_Copy_8.png
--------------------------------------------------------------------------------
/.github/assets/Look.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/Look.png
--------------------------------------------------------------------------------
/.github/assets/favicon-24x24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/favicon-24x24.png
--------------------------------------------------------------------------------
/.github/assets/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/favicon-32x32.png
--------------------------------------------------------------------------------
/.github/assets/favicon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/favicon-48x48.png
--------------------------------------------------------------------------------
/.github/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/icon.png
--------------------------------------------------------------------------------
/.github/assets/logo-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/logo-dark.png
--------------------------------------------------------------------------------
/.github/assets/logo-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/logo-light.png
--------------------------------------------------------------------------------
/.github/assets/rooks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/.github/assets/rooks.png
--------------------------------------------------------------------------------
/.github/assets/rooks.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 60
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 7
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | # Label to use when marking an issue as stale
10 | staleLabel: wontfix
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 | This issue has been automatically marked as stale because it has not had
14 | recent activity. It will be closed if no further activity occurs. Thank you
15 | for your contributions.
16 | # Comment to post when closing a stale issue. Set to `false` to disable
17 | closeComment: false
18 |
--------------------------------------------------------------------------------
/.github/workflows/contributors.yml:
--------------------------------------------------------------------------------
1 | name: All Contributors
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | concurrency: ${{ github.workflow }}-${{ github.ref }}
9 |
10 | jobs:
11 | update-contributors:
12 | if: github.repository == 'imbhargav5/rooks'
13 |
14 | timeout-minutes: 20
15 |
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 | - uses: ./.github/actions/ci-setup
21 | # - uses: ./.github/actions/ci-checks
22 | - name: Generate list of contributors
23 | run: |
24 | pnpm contributors:update
25 | pnpm contributors:generate
26 | - name: Auto update Readme
27 | run: |
28 | pnpm update-package-list-to-markdown
29 | - name: Create or Update Pull request
30 | id: cpr
31 | uses: peter-evans/create-pull-request@v4
32 | with:
33 | token: ${{ secrets.GITHUB_TOKEN }}
34 | branch: actions/all-contributors-update
35 | commit-message: Update Contributors List in Readme
36 | title: Update Contributors List in Readme
37 | body: Automatically generating contributors
38 | delete-branch: true
39 | labels: all-contributors-update
40 | draft: false
41 |
--------------------------------------------------------------------------------
/.github/workflows/pr.yml:
--------------------------------------------------------------------------------
1 | name: Node CI Pull request
2 | concurrency:
3 | group: pr-${{ github.event.pull_request.number || github.ref }}
4 | cancel-in-progress: true
5 | on:
6 | pull_request:
7 | branches:
8 | - "**"
9 |
10 | jobs:
11 | build:
12 | timeout-minutes: 20
13 |
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - uses: actions/checkout@v4
18 | - uses: ./.github/actions/ci-setup
19 | - name: run all checks and get coverage
20 | run: pnpm run all-checks
21 | - name: Upload coverage to Codecov
22 | uses: codecov/codecov-action@v2
23 | with:
24 | directory: packages/rooks/src/coverage
25 | size-limit:
26 | timeout-minutes: 20
27 | runs-on: ubuntu-latest
28 | steps:
29 | - uses: actions/checkout@v4
30 | - uses: ./.github/actions/ci-setup
31 | - uses: andresz1/size-limit-action@v1.7.0
32 | with:
33 | directory: "packages/rooks"
34 | github_token: ${{ secrets.GITHUB_TOKEN }}
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | /.package.json
3 | package-lock.json
4 | lib
5 | yarn-error.log
6 | .next
7 | out
8 | dist
9 | lerna-debug.log
10 | .cache
11 | coverage
12 | /*.tsbuildinfo
13 | .out
14 | .DS_Store
15 | yarn-error*
16 | .rpt2_cache
17 | .github/actions/**/node_modules
18 | !.github/actions/**/package-lock.json
19 | *.d.ts
20 | .changelog
21 | **/tsconfig.tsbuildinfo
22 | src/declarations
23 |
24 |
25 | .docusaurus/*
26 | translated_docs
27 | build/
28 | yarn.lock
29 | i18n/*
30 |
31 | # local env files
32 | .env.local
33 | .env.development.local
34 | .env.test.local
35 | .env.production.local
36 |
37 | # turbo
38 | .turbo
39 | .vercel
40 |
41 |
42 | # content-collections
43 | .content-collections/
44 |
45 | .jest-cache
--------------------------------------------------------------------------------
/.husky/_/husky.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | if [ -z "$husky_skip_init" ]; then
3 | debug () {
4 | if [ "$HUSKY_DEBUG" = "1" ]; then
5 | echo "husky (debug) - $1"
6 | fi
7 | }
8 |
9 | readonly hook_name="$(basename -- "$0")"
10 | debug "starting $hook_name..."
11 |
12 | if [ "$HUSKY" = "0" ]; then
13 | debug "HUSKY env variable is set to 0, skipping hook"
14 | exit 0
15 | fi
16 |
17 | if [ -f ~/.huskyrc ]; then
18 | debug "sourcing ~/.huskyrc"
19 | . ~/.huskyrc
20 | fi
21 |
22 | readonly husky_skip_init=1
23 | export husky_skip_init
24 | sh -e "$0" "$@"
25 | exitCode="$?"
26 |
27 | if [ $exitCode != 0 ]; then
28 | echo "husky - $hook_name hook exited with code $exitCode (error)"
29 | fi
30 |
31 | if [ $exitCode = 127 ]; then
32 | echo "husky - command not found in PATH=$PATH"
33 | fi
34 |
35 | exit $exitCode
36 | fi
37 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | if [[ $IS_GH_ACTION != 1 ]]; then node_modules/.bin/lint-staged; fi;
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | queue_rules:
2 | - name: default
3 | # speculative_checks: 3
4 | # batch_size: 2
5 | conditions:
6 | - check-success=Build (test)
7 | - check-success=Test (yarn test)
8 | pull_request_rules:
9 | - name: update out-of-sync PR
10 | conditions:
11 | - base=master
12 | - -conflict
13 | - -draft
14 | actions:
15 | update:
16 | - name: Automatic merge on approval
17 | conditions:
18 | - "#approved-reviews-by>=1"
19 | actions:
20 | merge:
21 | method: merge
22 | - name: close stale pull request
23 | conditions:
24 | - base=master
25 | - -closed
26 | - updated-at<14 days ago
27 | actions:
28 | close:
29 | message: |
30 | This pull request looks stale. Feel free to reopen it if you think it is a mistake.
31 | - name: merge Renovate pull request
32 | conditions:
33 | - author=renovate[bot]
34 | - label=dependency-update
35 | - label!=major
36 | actions:
37 | review:
38 | type: APPROVE
39 | message: Automatically approving Renovate
40 | queue:
41 | name: default
42 | method: rebase
43 | priority: low
44 | - name: close Renovate pull request (conflict)
45 | conditions:
46 | - conflict
47 | - author=renovate[bot]
48 | - label=dependency-update
49 | actions:
50 | close:
51 | message: |
52 | This automated pull request has a conflict. Closing - Renovate will create a new PR.
53 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 22.14.0
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | dist
3 | out
4 | build
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true
5 | }
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.workingDirectories": [
3 | "./",
4 | { "pattern": "./apps/*/" },
5 | { "pattern": "./packages/*/" }
6 | ],
7 | "editor.defaultFormatter": "esbenp.prettier-vscode",
8 | "editor.formatOnSave": true,
9 | "editor.codeActionsOnSave": {
10 | "source.fixAll.eslint": "explicit"
11 | },
12 | "eslint.options": {
13 | "cache": true
14 | },
15 | "typescript.tsdk": "node_modules/typescript/lib",
16 | "eslint.packageManager": "yarn",
17 | "eslint.validate": [
18 | "javascript",
19 | "javascriptreact",
20 | "typescript",
21 | "typescriptreact",
22 | "yaml"
23 | ],
24 | "files.exclude": {
25 | "**/.git": true,
26 | "**/.svn": true,
27 | "**/.hg": true,
28 | "**/CVS": true,
29 | "**/.DS_Store": true,
30 | "**/node_modules": false
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | Please check the releases section.
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 react-hooks-org
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MAINTENANCE.md:
--------------------------------------------------------------------------------
1 | # Maintenance
2 |
3 | ## Commands for maintaining
4 |
5 | 1. To build custom github actions in ./.github/actions folder
6 |
7 | Run this in the root folder of the project
8 |
9 | ```sh
10 | yarn build:custom-github-actions
11 | ```
12 |
--------------------------------------------------------------------------------
/apps/website/content-collections.ts:
--------------------------------------------------------------------------------
1 | import { defineCollection, defineConfig } from '@content-collections/core';
2 | import {
3 | createMetaSchema,
4 | createDocSchema,
5 | transformMDX,
6 | } from '@fumadocs/content-collections/configuration';
7 |
8 | const docs = defineCollection({
9 | name: 'docs',
10 | directory: 'content/docs',
11 | include: '**/*.mdx',
12 | schema: createDocSchema,
13 | transform: transformMDX,
14 | });
15 |
16 | const metas = defineCollection({
17 | name: 'meta',
18 | directory: 'content/docs',
19 | include: '**/meta.json',
20 | parser: 'json',
21 | schema: createMetaSchema,
22 | });
23 |
24 | export default defineConfig({
25 | collections: [docs, metas],
26 | });
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/meta.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Hooks",
3 | "icon": "Home",
4 | "root": true
5 | }
6 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useArrayState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useArrayState
3 | title: useArrayState
4 | sidebar_label: useArrayState
5 | ---
6 |
7 | ## About
8 |
9 | Array state manager hook for React. It exposes push**, **pop, unshift, shift, concat, fill and reverse methods to be able to easily modify the state of an array.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import { useArrayState, useInput } from "rooks";
15 | export default function App() {
16 | const [array, controls] = useArrayState([1, 2, 3]);
17 | const numberInput = useInput(0);
18 |
19 | return (
20 |
21 |
Array items are - {array.join(",")}
22 |
23 |
32 |
33 | );
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useAsyncEffect.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useAsyncEffect
3 | title: useAsyncEffect
4 | sidebar_label: useAsyncEffect
5 | ---
6 |
7 | ## About
8 |
9 | This is a version of `useEffect` that accepts an async function.
10 |
11 | `useEffect` only works with effect functions that run synchronously. The go-to solution for most people is to simply run an async function inside `useEffect`, but that approach has a lot of gotchas involving React state manipulation.
12 |
13 | [//]: # "Main"
14 |
15 | ## Examples
16 |
17 | ### Basic example
18 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useDebounce.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDebounce
3 | title: useDebounce
4 | sidebar_label: useDebounce
5 | ---
6 |
7 | ## About
8 |
9 | Debounce hook for react. Internally, it uses lodash debounce.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import React, { useState } from "react";
15 | import { useDebounce } from "rooks";
16 |
17 | export default function App() {
18 | const [value, setValue] = useState("");
19 | const setValueDebounced = useDebounce(setValue, 500);
20 |
21 | return (
22 |
23 |
setValueDebounced(e.target.value)}
25 | placeholder="Please type here"
26 | />
27 |
{value}
28 |
29 | );
30 | }
31 | ```
32 |
33 | ### Arguments
34 |
35 | | Argument | Type | Description | Default value |
36 | | -------- | -------- | ---------------------------------------- | ------------- |
37 | | callback | Function | The function to debounce | undefined |
38 | | wait | number | The duration to debounce in milliseconds | undefined |
39 | | options | Object | options to pass into lodash's debounce | {} |
40 |
41 | ### Return Value
42 |
43 | | Name | Type | Description |
44 | | ----------------- | -------- | ---------------------- |
45 | | debouncedFunction | Function | The debounced function |
46 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useDebounceFn.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDebounceFn
3 | title: useDebounceFn
4 | sidebar_label: useDebounceFn
5 | ---
6 |
7 | ## About
8 |
9 | Powerful debounce function hook for React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useDebounceFn} from "rooks"
15 | export default function App() {
16 | useDebounceFn();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useDeepCompareEffect.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDeepCompareEffect
3 | title: useDeepCompareEffect
4 | sidebar_label: useDeepCompareEffect
5 | ---
6 |
7 | ## About
8 |
9 | Deep compare dependencies instead of shallow for useEffect
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useDeepCompareEffect} from "rooks"
15 | export default function App() {
16 | useDeepCompareEffect();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useDidMount.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDidMount
3 | title: useDidMount
4 | sidebar_label: useDidMount
5 | ---
6 |
7 | ## About
8 |
9 | componentDidMount hook for React
10 |
11 |
12 | ## Examples
13 |
14 | ```jsx
15 | import { useDidMount } from "rooks";
16 | export default function App() {
17 | useDidMount(function() {
18 | console.log("mounted");
19 | });
20 | return null;
21 | }
22 | ```
23 |
24 | ## Arguments
25 |
26 | | Argument | Type | Description |
27 | | -------- | -------- | ------------------------------ |
28 | | callback | function | function to be called on mount |
29 |
30 | ---
31 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useDidUpdate.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDidUpdate
3 | title: useDidUpdate
4 | sidebar_label: useDidUpdate
5 | ---
6 |
7 | ## About
8 |
9 | componentDidUpdate hook for react
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import React, { useState } from "react";
15 | import { useDidUpdate } from "rooks";
16 |
17 | export default function App() {
18 | const [value, setValue] = useState(0);
19 | useDidUpdate(() => {
20 | console.log("This message was logged on update.");
21 | });
22 | return (
23 |
24 |
Update this value by clicking on the button
25 |
Current value is {value}
26 |
Open the sandbox in codesandbox to view the console
27 |
28 |
29 | );
30 | }
31 | ```
32 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useDocumentEventListener.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDocumentEventListener
3 | title: useDocumentEventListener
4 | sidebar_label: useDocumentEventListener
5 | ---
6 |
7 | ## About
8 |
9 | A react hook to an event listener to the document object
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import { useDocumentEventListener } from "rooks";
17 | import { useState, useEffect } from "react";
18 |
19 | export default function App() {
20 | const [myState, setMyState] = useState(0);
21 |
22 | useDocumentEventListener("click", function() {
23 | setMyState(myState + 1);
24 | });
25 |
26 | return (
27 |
28 |
useDocumentEventListener Example
29 |
30 | Clicked {myState} times
31 |
32 | );
33 | }
34 | ```
35 |
36 | ### Arguments
37 |
38 | | Arguments | Type | Description | Default value |
39 | | -------------- | -------- | ---------------------------------------------- | ------------- |
40 | | eventName | string | The event to track | undefind |
41 | | callback | function | The callback to be called on event | undefined |
42 | | conditions | object | The options to be passed to the event listener | {} |
43 | | isLayoutEffect | boolean | Should it use layout effect. Defaults to false | false |
44 |
45 | ### Return
46 |
47 | No return value.
48 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useDocumentVisibilityState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDocumentVisibilityState
3 | title: useDocumentVisibilityState
4 | sidebar_label: useDocumentVisibilityState
5 | ---
6 |
7 | ## About
8 |
9 | Returns the visibility state of the document. Returns `null` on the server.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useEffect} from 'react'
15 | import {useDocumentVisibilityState} from "rooks"
16 |
17 | export default function App() {
18 | const isDocumentVisible = useDocumentVisibilityState();
19 | useEffect(() => {
20 | console.log(isDocumentVisible)
21 | }, [isDocumentVisible])
22 | return Try switching to a different tab and check console
23 | }
24 | ```
25 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useEffectOnceWhen.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useEffectOnceWhen
3 | title: useEffectOnceWhen
4 | sidebar_label: useEffectOnceWhen
5 | ---
6 |
7 | ## About
8 |
9 | Runs a callback effect atmost one time when a condition becomes true
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import { useState } from "react";
17 | import { useEffectOnceWhen } from "rooks";
18 |
19 | const App = () => {
20 | const [loading, setLoading] = useState(true);
21 |
22 | useEffectOnceWhen(() => {
23 | setTimeout(() => {
24 | setLoading(false);
25 | }, 3000); // Countdown for 3 sec
26 | }, loading);
27 |
28 | return (
29 |
30 |
Rooks: useEffectOnceWhen Example
31 |
32 |
33 |
34 | {loading
35 | ? "Loading Component (will be gone in 3 secs)...."
36 | : "Counter Component"}
37 |
38 |
39 | );
40 | };
41 |
42 | export default App;
43 | ```
44 |
45 | ### Arguments
46 |
47 | | Arguments | Type | Description | Default value |
48 | | --------- | -------- | ------------------------------------ | ------------- |
49 | | callback | function | The callback to be called | undefined |
50 | | when | boolean | The condition which needs to be true | true |
51 |
52 | ### Return
53 |
54 | No return value.
55 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useFileDropRef.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFileDropRef
3 | title: useFileDropRef
4 | sidebar_label: useFileDropRef
5 | ---
6 |
7 | ## About
8 |
9 | Drop files easily
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useFileDropRef } from "rooks";
15 | export default function App() {
16 | useFileDropRef();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useFocus.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFocus
3 | title: useFocus
4 | sidebar_label: useFocus
5 | ---
6 |
7 | ## About
8 |
9 | Handles focus events for the immediate target element.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useFocus } from "rooks";
15 | export default function App() {
16 | const [isFocus, setIsFocus] = useState(false);
17 | const { focusProps } = useFocus({
18 | onFocus: () => {
19 | console.log("focus");
20 | },
21 | onBlur: () => {
22 | console.log("blur");
23 | },
24 | onFocusChange: (isFocused) => {
25 | setIsFocus(isFocused);
26 | },
27 | });
28 |
29 | return (
30 |
39 | );
40 | }
41 | ```
42 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useFocusWithin.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFocusWithin
3 | title: useFocusWithin
4 | sidebar_label: useFocusWithin
5 | ---
6 |
7 | ## About
8 |
9 | Handles focus events for the target component.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useState } from "react";
15 | import { useFocusWithin } from "rooks";
16 |
17 | const Page = () => {
18 | const [isFocusWithin, setIsFocusWithin] = useState(false);
19 | const { focusWithinProps } = useFocusWithin({
20 | onFocusWithin: () => {
21 | console.log("focus within");
22 | },
23 | onBlurWithin: () => {
24 | console.log("blur within");
25 | },
26 | onFocusWithinChange: (isFocusWithin) => {
27 | setIsFocusWithin(isFocusWithin);
28 | },
29 | });
30 |
31 | return (
32 |
43 |
46 |
49 |
50 | );
51 | };
52 | export default Page;
53 | ```
54 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useFreshCallback.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFreshCallback
3 | title: useFreshCallback
4 | sidebar_label: useFreshCallback
5 | ---
6 |
7 | ## About
8 |
9 | Avoid stale closures and keep your callback fresh
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useFreshCallback} from "rooks"
15 | export default function App() {
16 | useFreshCallback();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useGetIsMounted.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useGetIsMounted
3 | title: useGetIsMounted
4 | sidebar_label: useGetIsMounted
5 | ---
6 |
7 | ## About
8 |
9 | Checks if a component is mounted or not at the time. Useful for async effects
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic usage
16 |
17 | ```jsx
18 | import { useEffect } from "react";
19 | import { useGetIsMounted } from "rooks";
20 | export default function App() {
21 | const getIsMounted = useGetIsMounted();
22 | useEffect(() => {
23 | alert("Mounted " + String(getIsMounted()));
24 | }, []);
25 | return null;
26 | }
27 | ```
28 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useIsDroppingFiles.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useIsDroppingFiles
3 | title: useIsDroppingFiles
4 | sidebar_label: useIsDroppingFiles
5 | ---
6 |
7 | ## About
8 |
9 | Check if any files are currently being dropped anywhere. Useful for highlighting drop areas.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useIsDroppingFiles } from "rooks";
15 | export default function App() {
16 | useIsDroppingFiles();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useKeyBindings.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useKeyBindings
3 | title: useKeyBindings
4 | sidebar_label: useKeyBindings
5 | ---
6 |
7 | ## About
8 |
9 | useKeyBindings can bind pairs of keyboard events and handlers.
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import "./styles.css";
17 | import { useKeyBindings, useCounter } from "rooks";
18 |
19 | export default function App() {
20 | const { value, increment, incrementBy, decrementBy, reset } = useCounter(0);
21 | const cb1 = () => increment();
22 | const cb2 = () => decrementBy(3);
23 | const cb3 = () => incrementBy(5);
24 | const cb4 = () => reset();
25 |
26 | useKeyBindings({ a: cb1, b: cb2, Enter: cb3, Escape: cb4 });
27 |
28 | return (
29 |
30 |
31 | Counter value is : {value}
32 |
33 |
34 | );
35 | }
36 | ```
37 |
38 | ### Arguments
39 |
40 | | Argument | Type | Description | Default value |
41 | | ----------- | ------- | ------------------------------------- | ------------- |
42 | | keyBindings | Object | pairs of keyboard events and handlers | {} |
43 | | options | Options | refer to useKey | {} |
44 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useLifecycleLogger.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useLifecycleLogger
3 | title: useLifecycleLogger
4 | sidebar_label: useLifecycleLogger
5 | ---
6 |
7 | ## About
8 |
9 | A react hook that console logs parameters as component transitions through lifecycles.
10 |
11 | [//]: # "Main"
12 |
13 | ## Installation
14 |
15 | ## Examples
16 |
17 | ```jsx
18 | import "./styles.css";
19 | import { useLifecycleLogger } from "rooks";
20 | import { useEffect, useState } from "react";
21 |
22 | export default function App() {
23 | const [value, setValue] = useState(0);
24 |
25 | useEffect(() => {
26 | setValue(1);
27 | }, []);
28 |
29 | useLifecycleLogger("Demo", value);
30 |
31 | return (
32 |
33 |
useLifecycleLogger example
34 | See console for logs
35 |
36 | );
37 | }
38 | ```
39 |
40 | ### Arguments
41 |
42 | | Argument value | Type | Description | Defualt |
43 | | -------------- | ------ | -------------------------------------------------------- | ----------- |
44 | | componentName | String | The name of component to be shown in the log | "Component" |
45 | | rest | Array | An arry of variables to be logged in component lifecycle | undefined |
46 |
47 | ### Returns
48 |
49 | No return value
50 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useLockBodyScroll.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useLockBodyScroll
3 | title: useLockBodyScroll
4 | sidebar_label: useLockBodyScroll
5 | ---
6 |
7 | ## About
8 |
9 | Locks or unlocks body scroll
10 |
11 | ## Examples
12 |
13 | ### Basic
14 |
15 | ```tsx
16 | import { useState } from "react";
17 | import { useLockBodyScroll } from "rooks";
18 |
19 | export default function App() {
20 | const [isLocked, setIsLocked] = useState(false);
21 |
22 | // Lock body scroll when isLocked is true
23 | useLockBodyScroll(isLocked);
24 |
25 | return (
26 |
27 |
30 |
31 | );
32 | }
33 | ```
34 |
35 | ## Arguments
36 |
37 | | Argument | Type | Description |
38 | | -------- | ------- | ------------------------------------------------ |
39 | | isLocked | boolean | Whether to lock or unlock scroll on the body tag |
40 |
41 | ---
42 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useMergeRefs.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMergeRefs
3 | title: useMergeRefs
4 | sidebar_label: useMergeRefs
5 | ---
6 |
7 | ## About
8 |
9 | Merges any number of refs into a single ref
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import "./styles.css";
17 | import { useMergeRefs, useEventListenerRef } from "rooks";
18 |
19 | function App() {
20 | const mousedownRef = useEventListenerRef("mousedown", () => {
21 | console.log("mouse down");
22 | });
23 | const mouseupRef = useEventListenerRef("mouseup", () => {
24 | console.log("mouse up");
25 | });
26 | const refs = useMergeRefs(mousedownRef, mouseupRef);
27 |
28 | return (
29 |
30 |
Rooks : useMergeRefs Example
31 |
32 |
40 | A div with multiple refs. Click me!!
41 |
42 |
43 | );
44 | }
45 | export default App;
46 | ```
47 |
48 | ### Arguments
49 |
50 | | Argument value | Type | Description |
51 | | -------------- | ----- | -------------------------------------------------------------------- |
52 | | refs | Array | Takes any number of refs. Refs can be mutable refs or function refs. |
53 |
54 | ### Returns
55 |
56 | | Return value | Type | Description |
57 | | ------------ | ----------- | ----------- |
58 | | ref | CallbackRef | Merged ref |
59 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useMouse.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMouse
3 | title: useMouse
4 | sidebar_label: useMouse
5 | ---
6 |
7 | ## About
8 |
9 | ### Description
10 |
11 | Mouse position hook for React.
12 |
13 |
14 | ### Return value
15 |
16 | useMouse returns a single object containing the mouse position.
17 |
18 | | Returned object attributes | Type | Description |
19 | | -------------------------- | ---- | ------------------- |
20 | | x | int | X position of mouse |
21 | | y | int | Y position of mouse |
22 |
23 |
24 | ## Examples
25 | ### Basic Usage
26 |
27 | ```jsx
28 | import { useMouse } from "rooks";
29 |
30 | export default function App() {
31 | const { x, y } = useMouse();
32 | return (
33 | <>
34 | Move mouse here to see changes to position
35 | X position is {x || "null"}
36 | X position is {y || "null"}
37 | >
38 | );
39 | }
40 | ```
41 |
42 |
43 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useMouseMoveDelta.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMouseMoveDelta
3 | title: useMouseMoveDelta
4 | sidebar_label: useMouseMoveDelta
5 | ---
6 |
7 | ## About
8 |
9 | Tracks delta of mouse move
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useMouseMoveDelta} from "rooks"
15 | export default function App() {
16 | useMouseMoveDelta();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useMouseWheelDelta.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMouseWheelDelta
3 | title: useMouseWheelDelta
4 | sidebar_label: useMouseWheelDelta
5 | ---
6 |
7 | ## About
8 |
9 | Tracks delta of mouse move
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useMouseWheelDelta} from "rooks"
15 | export default function App() {
16 | useMouseWheelDelta();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useNativeMapState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useNativeMapState
3 | title: useNativeMapState
4 | sidebar_label: useNativeMapState
5 | ---
6 |
7 | ## About
8 |
9 | Manage Map() object state in React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useNativeMapState } from "rooks";
15 | export default function App() {
16 | useNativeMapState();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useNavigatorLanguage.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useNavigatorLanguage
3 | title: useNavigatorLanguage
4 | sidebar_label: useNavigatorLanguage
5 | ---
6 |
7 | ## About
8 |
9 | Navigator Language hook for React.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useNavigatorLanguage } from "rooks";
16 |
17 | function App() {
18 | const language = useNavigatorLanguage();
19 |
20 | return (
21 |
24 |
Rooks : useNavigatorLanguage example
25 |
26 | Language is {language}
27 |
28 |
29 | );
30 | }
31 |
32 | export default App;
33 | ```
34 |
35 | ### Return value
36 |
37 | A language (String) is returned.
38 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useOnClickRef.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnClickRef
3 | title: useOnClickRef
4 | sidebar_label: useOnClickRef
5 | ---
6 |
7 | ## About
8 |
9 | Callback on click/tap events
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useOnClickRef } from "rooks";
15 | export default function App() {
16 | useOnClickRef();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useOnHoverRef.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnHoverRef
3 | title: useOnHoverRef
4 | sidebar_label: useOnHoverRef
5 | ---
6 |
7 | ## About
8 |
9 | On hover callback hook
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useOnHoverRef} from "rooks"
15 | export default function App() {
16 | useOnHoverRef();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useOnWindowResize.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnWindowResize
3 | title: useOnWindowResize
4 | sidebar_label: useOnWindowResize
5 | ---
6 |
7 | ## About
8 |
9 | A React hook for adding an event listener for window resize
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useOnWindowResize } from "rooks";
16 |
17 | export default function App() {
18 | useOnWindowResize(() => console.log("window resized"));
19 |
20 | return (
21 |
22 |
useOnWindowResize example
23 | Resize the window and see the logs
24 |
25 | );
26 | }
27 | ```
28 |
29 | ### Arguments
30 |
31 | | Arguments | Type | Description | Default value |
32 | | -------------- | -------- | ----------------------------------------------- | ------------- |
33 | | callback | function | Callback function which needs to run on unmount | undefined |
34 | | when | boolean | When the event handler should be active | true |
35 | | isLayoutEffect | boolean | Should it use layout effect. | false |
36 |
37 | ### Returns
38 |
39 | No return value.
40 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useOnline.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnline
3 | title: useOnline
4 | sidebar_label: useOnline
5 | ---
6 |
7 | ## About
8 |
9 | Online status hook for React.
10 |
11 | ### Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useOnline } from "rooks";
16 |
17 | function App() {
18 | const online = useOnline();
19 | console.log("I'm online");
20 |
21 | return (
22 |
23 |
Rooks: useOnline example
24 |
25 |
26 |
27 | Status:You are {online ? "Online" : "Offline"}
28 |
29 |
30 | );
31 | }
32 |
33 | export default App;
34 | ```
35 |
36 | ### Return value
37 |
38 | Offline status (boolean) is returned.
39 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useOrientation.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOrientation
3 | title: useOrientation
4 | sidebar_label: useOrientation
5 | ---
6 |
7 | ## About
8 |
9 | orientation hook for react
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useOrientation} from "rooks"
15 | export default function App() {
16 | useOrientation();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/usePromise.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: usePromise
3 | title: usePromise
4 | sidebar_label: usePromise
5 | ---
6 |
7 | ## About
8 |
9 | Promise management hook for react
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {usePromise} from "rooks"
15 | export default function App() {
16 | usePromise();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useRenderCount.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useRenderCount
3 | title: useRenderCount
4 | sidebar_label: useRenderCount
5 | ---
6 |
7 | ## About
8 |
9 | Get the render count of a component
10 |
11 | ## Examples
12 |
13 | TODO: Add an example here.
14 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useSafeSetState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSafeSetState
3 | title: useSafeSetState
4 | sidebar_label: useSafeSetState
5 | ---
6 |
7 | ## About
8 |
9 | set state but ignores if component has already unmounted
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useSafeSetState} from "rooks"
15 | export default function App() {
16 | useSafeSetState();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useSessionstorageState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSessionstorageState
3 | title: useSessionstorageState
4 | sidebar_label: useSessionstorageState
5 | ---
6 |
7 | ## About
8 |
9 | useState but syncs with sessionstorage
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import "./styles.css";
17 | import React from "react";
18 | import { useSessionstorageState } from "rooks";
19 |
20 | export default function App() {
21 | const [count, setCount] = useSessionstorageState("my-app:count", 0);
22 |
23 | return (
24 |
25 |
Rooks : useSessionstorageState
26 |
Refresh the page to see the previous value in tact
27 |
28 |
29 |
30 | );
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useSetState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSetState
3 | title: useSetState
4 | sidebar_label: useSetState
5 | ---
6 |
7 | ## About
8 |
9 | Manage the state of a Set in React. Exposes add, delete and clear methods along with the current set to easily manipulate values in a set.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import { useSetState } from "rooks";
15 | export default function App() {
16 | useSetState();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useSpeech.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSpeech
3 | title: useSpeech
4 | sidebar_label: useSpeech
5 | ---
6 |
7 | ## About
8 |
9 | Speech synthesis hook for React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useSpeech} from "rooks"
15 | export default function App() {
16 | useSpeech();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useTimeTravelState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useTimeTravelState
3 | title: useTimeTravelState
4 | sidebar_label: useTimeTravelState
5 | ---
6 |
7 | ## About
8 |
9 | A hook that manages state which can undo and redo. A more powerful version of useUndoState hook.
10 |
11 | ## Examples
12 |
13 | ### Basic example
14 |
15 | ```tsx
16 | import { useTimeTravelState } from "rooks";
17 | export default function App() {
18 | const [value, setValue, controls] = useTimeTravelState(0);
19 |
20 | return (
21 |
22 |
Current value: {value}
23 |
24 |
25 | Can undo: {String(controls.canUndo)}
26 | Can redo: {String(controls.canRedo)}
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useTimeoutWhen.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useTimeoutWhen
3 | title: useTimeoutWhen
4 | sidebar_label: useTimeoutWhen
5 | ---
6 |
7 | ## About
8 |
9 | Takes a callback and fires it when a condition is true
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic usage
16 |
17 | ```jsx
18 | import "./styles.css";
19 | import { useTimeoutWhen } from "rooks";
20 | import { useState } from "react";
21 |
22 | function App() {
23 | const [start, setStart] = useState(false);
24 | useTimeoutWhen(() => setStart(false), 2000, start);
25 | return (
26 | <>
27 | Rooks: useTimeoutWhen example
28 |
29 | Click the button below to disable it for 2 seconds
30 |
33 | >
34 | );
35 | }
36 |
37 | export default App;
38 | ```
39 |
40 | ### Arguments
41 |
42 | | Arguments | Type | Description | Default value |
43 | | --------- | -------- | -------------------------------------------------------- | ------------- |
44 | | callback | function | Function to be executed in timeout | undefind |
45 | | delay | Number | Number in milliseconds after which callback is to be run | 0 |
46 | | when | boolean | The condition which when true, sets the timeout | true |
47 |
48 | ### Returned
49 |
50 | No return value.
51 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useUndoRedoState.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useUndoRedoState
3 | title: useUndoRedoState
4 | sidebar_label: useUndoRedoState
5 | ---
6 |
7 | ## About
8 |
9 | Setstate but can also undo and redo
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useUndoRedoState} from "rooks"
15 | export default function App() {
16 | useUndoRedoState();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useVibrate.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useVibrate
3 | title: useVibrate
4 | sidebar_label: useVibrate
5 | ---
6 |
7 | ## About
8 |
9 | Vibration API hook for React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useVibrate} from "rooks"
15 | export default function App() {
16 | useVibrate();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useVideo.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useVideo
3 | title: useVideo
4 | sidebar_label: useVideo
5 | ---
6 |
7 | ## About
8 |
9 | Video hook for react
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useVideo} from "rooks"
15 | export default function App() {
16 | useVideo();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useWhyDidYouUpdate.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWhyDidYouUpdate
3 | title: useWhyDidYouUpdate
4 | sidebar_label: useWhyDidYouUpdate
5 | ---
6 |
7 | ## About
8 |
9 | A hook that can track which value change caused a rerender
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useWhyDidYouUpdate} from "rooks"
15 | export default function App() {
16 | useWhyDidYouUpdate();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useWillUnmount.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWillUnmount
3 | title: useWillUnmount
4 | sidebar_label: useWillUnmount
5 | ---
6 |
7 | ### About
8 |
9 | A React hook for componentWillUnmount lifecycle method.
10 |
11 | ### Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useState } from "react";
16 | import { useWillUnmount } from "rooks";
17 |
18 | function Message() {
19 | useWillUnmount(function(props) {
20 | console.log("UNMOUNT", props);
21 | });
22 | return This component will unmount
;
23 | }
24 |
25 | const App = () => {
26 | const [shouldRender, enableRender] = useState(true);
27 | return (
28 |
29 |
Rook: useWillUnmount Example
30 |
31 |
32 |
39 |
40 |
Check or Uncheck the box
41 |
enableRender(!shouldRender)} type="checkBox" />
42 |
43 | {shouldRender &&
}
44 |
45 |
46 | );
47 | };
48 |
49 | export default App;
50 | ```
51 |
52 | #### Arguments
53 |
54 | | Arguments | Type | Description | Default value |
55 | | --------- | -------- | ----------------------------------------------- | ------------- |
56 | | callback | function | Callback function which needs to run on unmount | undefined |
57 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useWindowEventListener.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWindowEventListener
3 | title: useWindowEventListener
4 | sidebar_label: useWindowEventListener
5 | ---
6 |
7 | ## About
8 |
9 | Adds an event listener to window
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic usage
16 |
17 | ```jsx
18 | import { useState } from "react";
19 | import { useWindowEventListener } from "rooks";
20 | import "./styles.css";
21 |
22 | export default function App() {
23 | const [value, setValue] = useState(0);
24 | useWindowEventListener("click", function() {
25 | setValue(value + 1);
26 | });
27 | return (
28 |
34 |
Click anywhere
35 |
Value is {value}
36 |
37 | );
38 | }
39 | ```
40 |
41 | ---
42 |
--------------------------------------------------------------------------------
/apps/website/content/docs/hooks/useWindowScrollPosition.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWindowScrollPosition
3 | title: useWindowScrollPosition
4 | sidebar_label: useWindowScrollPosition
5 | ---
6 |
7 | ## About
8 |
9 | A React hook to get the scroll position of the window
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic Usage
16 |
17 | ```jsx
18 | import "./styles.css";
19 | import { useWindowScrollPosition } from "rooks";
20 |
21 | function App() {
22 | const position = useWindowScrollPosition(); // default config: { wait = 100, passive = true }
23 | console.log(position); // {x: ..., y: ...}
24 | return (
25 |
26 |
Rooks : useWindowScrollPosition Example
27 |
28 |
29 |
Scroll
30 |
{JSON.stringify(position)}
31 |
32 | );
33 | }
34 |
35 | export default App;
36 | ```
37 |
--------------------------------------------------------------------------------
/apps/website/content/docs/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Rooks.js
3 | ---
4 |
5 | ## Introduction
6 |
7 | Essential React custom hooks ⚓ to super charge your components!
8 |
9 | ## Contributors
10 |
11 |
12 |
--------------------------------------------------------------------------------
/apps/website/dump-contributors.ts:
--------------------------------------------------------------------------------
1 | import { readFileSync, writeFileSync } from 'fs';
2 | import { join } from 'path';
3 | import { findUpSync } from 'find-up';
4 |
5 | const contributorsConfigPath = findUpSync('.all-contributorsrc');
6 |
7 | if (!contributorsConfigPath) {
8 | throw new Error('.all-contributorsrc file not found');
9 | }
10 |
11 | const fileToWritePath = join(__dirname, 'src/components/contributors-list-data.ts');
12 |
13 | const contributorsData = JSON.parse(readFileSync(contributorsConfigPath, 'utf-8'));
14 |
15 | writeFileSync(fileToWritePath, `export const contributorsListData = ${JSON.stringify(contributorsData, null, 2)}`);
16 |
17 |
18 |
--------------------------------------------------------------------------------
/apps/website/eslint.config.js:
--------------------------------------------------------------------------------
1 | import { nextJsConfig } from "@repo/eslint-config/next-js";
2 |
3 | /** @type {import("eslint").Linter.Config} */
4 | export default nextJsConfig;
5 |
--------------------------------------------------------------------------------
/apps/website/next.config.ts:
--------------------------------------------------------------------------------
1 | import { withContentCollections } from '@content-collections/next';
2 | import { NextConfig } from 'next';
3 |
4 | const config: NextConfig = {
5 | images: {
6 | domains: ['avatars.githubusercontent.com'],
7 | unoptimized: true,
8 | },
9 | async redirects() {
10 | return [
11 | {
12 | source: '/',
13 | destination: '/docs',
14 | permanent: false,
15 | },
16 | ];
17 | },
18 | };
19 |
20 | export default withContentCollections(config);
21 |
--------------------------------------------------------------------------------
/apps/website/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | "@tailwindcss/postcss": {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/apps/website/source.ts:
--------------------------------------------------------------------------------
1 | import { allDocs, allMetas } from 'content-collections';
2 | import { loader } from 'fumadocs-core/source';
3 | import { createMDXSource } from '@fumadocs/content-collections';
4 |
5 | export const source = loader({
6 | baseUrl: '/docs',
7 | source: createMDXSource(allDocs, allMetas),
8 | });
--------------------------------------------------------------------------------
/apps/website/src/app/api/search/route.tsx:
--------------------------------------------------------------------------------
1 | import { createFromSource } from 'fumadocs-core/search/server';
2 | import { source } from '../../../../source';
3 |
4 | export const { GET } = createFromSource(source);
--------------------------------------------------------------------------------
/apps/website/src/app/docs/docs.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss";
2 | @import "fumadocs-ui/css/neutral.css";
3 | @import "fumadocs-ui/css/preset.css";
4 |
5 | /* path of `fumadocs-ui` relative to the CSS file */
6 | @source '../../../node_modules/fumadocs-ui/dist/**/*.js';
7 |
--------------------------------------------------------------------------------
/apps/website/src/app/docs/layout.tsx:
--------------------------------------------------------------------------------
1 | import { source } from '../../../source';
2 | import { DocsLayout } from 'fumadocs-ui/layouts/docs';
3 | import type { ReactNode } from 'react';
4 | import { baseOptions } from '../../app/layout.config';
5 | import './docs.css';
6 |
7 | export default function Layout({ children }: { children: ReactNode }) {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | }
--------------------------------------------------------------------------------
/apps/website/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss";
2 |
--------------------------------------------------------------------------------
/apps/website/src/app/layout.config.tsx:
--------------------------------------------------------------------------------
1 | import { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
2 |
3 | export const baseOptions: BaseLayoutProps = {
4 | nav: {
5 | title: 'Rooks',
6 | },
7 | };
--------------------------------------------------------------------------------
/apps/website/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import { RootProvider } from 'fumadocs-ui/provider';
2 | import type { ReactNode } from 'react';
3 | import { QueryProvider } from '../providers/QueryProvider';
4 | import './globals.css';
5 |
6 | export default function Layout({ children }: { children: ReactNode }) {
7 | return (
8 |
9 |
17 |
18 | {children}
19 |
20 |
21 |
22 | );
23 | }
--------------------------------------------------------------------------------
/apps/website/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useRouter } from "next/navigation";
4 | import { useEffect } from "react";
5 |
6 | export default function Page() {
7 | const router = useRouter();
8 | useEffect(() => {
9 | router.replace('/docs');
10 | }, []);
11 | return null;
12 | }
13 |
--------------------------------------------------------------------------------
/apps/website/src/components/ClientHightlightWrapper.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 | import dynamic from "next/dynamic";
3 | import { ComponentProps, PropsWithoutRef } from "react";
4 |
5 | const ClientHighlight = dynamic(
6 | () => import('./ClientHighlight').then(mod => mod.ClientHighlight),
7 | { ssr: false }
8 | );
9 |
10 |
11 | export function ClientHightlightWrapper(props: ComponentProps) {
12 | return ;
13 | }
--------------------------------------------------------------------------------
/apps/website/src/pages/_app.tsx.old:
--------------------------------------------------------------------------------
1 | import { globalCss, NextUIProvider } from "@nextui-org/react";
2 | import { AppProps } from "next/app";
3 | import { MDXProvider } from "@mdx-js/react";
4 | import { components } from "../components/MDXRenderer/components";
5 |
6 | const globalStyles = globalCss({
7 | "*": { margin: 0, padding: 0, boxSizing: "border-box" },
8 | mark: {
9 | backgroundColor: "lightblue",
10 | padding: "2px 6px",
11 | fontWeight: 500,
12 | borderRadius: 6,
13 | },
14 | hr: {
15 | border: "1px solid $gray-300",
16 | margin: "1rem 0",
17 | },
18 | br: {
19 | display: "block",
20 | content: "",
21 | margin: "1rem 0",
22 | },
23 | });
24 |
25 | function MyApp({ Component, pageProps }: AppProps) {
26 | globalStyles();
27 | return (
28 | // 2. Use at the root of your app
29 |
30 |
31 |
32 |
33 |
34 | );
35 | }
36 |
37 | export default MyApp;
38 |
--------------------------------------------------------------------------------
/apps/website/src/pages/_document.tsx.old:
--------------------------------------------------------------------------------
1 | import { Children } from "react";
2 | import Document, {
3 | Html,
4 | Head,
5 | Main,
6 | NextScript,
7 | DocumentContext,
8 | DocumentInitialProps,
9 | } from "next/document";
10 | import { CssBaseline } from "@nextui-org/react";
11 | import { getSandpackCssText } from "@codesandbox/sandpack-react";
12 |
13 | class MyDocument extends Document {
14 | static async getInitialProps(
15 | ctx: DocumentContext
16 | ): Promise {
17 | const initialProps = await Document.getInitialProps(ctx);
18 | return {
19 | ...initialProps,
20 | styles: <>{Children.toArray([initialProps.styles])}>,
21 | };
22 | }
23 |
24 | render() {
25 | return (
26 |
27 |
28 | {CssBaseline.flush()}{" "}
29 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
43 | export default MyDocument;
44 |
--------------------------------------------------------------------------------
/apps/website/src/pages/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: getting-started
3 | title: Getting Started
4 | sidebar_label: Getting Started
5 | ---
6 |
7 |
8 |
9 | ### Installation
10 |
11 | npm i -s rooks
12 |
13 | ### Importing the hooks
14 |
15 | Import any hook from "rooks" and start using them!
16 |
17 | ```jsx
18 | import { useDidMount } from "rooks";
19 | ```
20 |
21 | ### Usage
22 |
23 | ```jsx
24 | function App() {
25 | useDidMount(() => {
26 | alert("mounted");
27 | });
28 | return (
29 |
30 |
Hello CodeSandbox
31 | Start editing to see some magic happen!
32 |
33 | );
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/apps/website/src/pages/home-sandbox.md:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/apps/website/src/pages/motivation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: motivation
3 | title: Motivation
4 | sidebar_label: Motivation
5 | ---
6 |
7 | When custom hooks were released by the **React.js** team, I was overwhelmed with excitement watching them show the amount of customization that can now be done with custom hooks.
8 |
9 | So that was a day I immediately decided to build **Rooks as a collection of custom hooks** that I would use for my projects regularly as a freelancer, or as a developer at my day.
10 |
11 | I would use so many components which use the same behaviour over and over again. And I would keep asking myself if there was a better way of composing this behaviour so that I don't have to write the same code over and over again.
12 |
13 | **Building a drop down, a model, or a form etec are all repetitive activities** that we as developers do on a day to day basis, and Rooks is an attempt to help you quickly build components as quickly as you can. I hope this proves as useful to you as it is to me.
14 |
--------------------------------------------------------------------------------
/apps/website/src/providers/QueryProvider.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4 | import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
5 | import { useState, type ReactNode } from 'react';
6 |
7 | interface QueryProviderProps {
8 | children: ReactNode;
9 | }
10 |
11 | export function QueryProvider({ children }: QueryProviderProps) {
12 | const [queryClient] = useState(
13 | () =>
14 | new QueryClient({
15 | defaultOptions: {
16 | queries: {
17 | staleTime: 60 * 1000, // 1 minute
18 | gcTime: 5 * 60 * 1000, // 5 minutes
19 | refetchOnWindowFocus: false,
20 | },
21 | },
22 | })
23 | );
24 |
25 | return (
26 |
27 | {children}
28 |
29 |
30 | );
31 | }
--------------------------------------------------------------------------------
/apps/website/src/utils/mdxSerialize.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import matter from "gray-matter";
3 | import { serialize } from "next-mdx-remote/serialize";
4 | import remarkGfm from "remark-gfm";
5 | import { MDXRemoteSerializeResult } from "next-mdx-remote";
6 |
7 | export const mdxSerialize = async (
8 | filePath: string
9 | ): Promise<{
10 | frontMatter: { [key: string]: unknown };
11 | mdxSource: MDXRemoteSerializeResult<
12 | Record,
13 | Record
14 | >;
15 | content: string;
16 | }> => {
17 | const markdownWithMeta = fs.readFileSync(filePath, "utf-8");
18 |
19 | const { data: frontMatter, content } = matter(markdownWithMeta);
20 | const mdxSource = await serialize<
21 | Record,
22 | Record
23 | >(content, {
24 | mdxOptions: {
25 | remarkPlugins: [remarkGfm],
26 | },
27 | });
28 | return {
29 | frontMatter,
30 | mdxSource,
31 | content,
32 | };
33 | };
34 |
--------------------------------------------------------------------------------
/apps/website/src/utils/url.ts:
--------------------------------------------------------------------------------
1 |
2 | import urlJoin from 'url-join';
3 | export function getUrl(path: string) {
4 | return urlJoin(process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000', path);
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/apps/website/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/nextjs.json",
3 | "compilerOptions": {
4 | "plugins": [
5 | {
6 | "name": "next"
7 | }
8 | ],
9 | "paths": {
10 | "content-collections": ["./.content-collections/generated"]
11 | },
12 | "baseUrl": "."
13 | },
14 | "include": [
15 | "**/*.ts",
16 | "**/*.tsx",
17 | "next-env.d.ts",
18 | "next.config.ts",
19 | ".next/types/**/*.ts"
20 | ],
21 | "exclude": ["node_modules"]
22 | }
23 |
--------------------------------------------------------------------------------
/data/docs/rooks.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: rooks
3 | title: rooks
4 | sidebar_label: rooks
5 | slug: /
6 | ---
7 |
8 |
9 |
10 |
11 |
12 | [](https://gyazo.com/742dc22ec370af0a96322427b6a32a9b)
13 |
14 | ## About
15 |
16 | Standalone build for all rooks. This package contains all the hooks built as part of the rooks project.
17 |
18 | **Note:** If you only need a few hooks from the rooks package, it's prefereable to install individiual hooks from npm instead of the standalone rooks build. In other words, install `@rooks/useDidMount` instead of `rooks` if you only need the `useDidMount` functionality.
19 |
20 | ## Installation
21 |
22 | npm i - s rooks
23 |
24 | Import any hook from "rooks" and start using them!
25 |
26 | ```jsx
27 | import { useDidMount } from "rooks";
28 | ```
29 |
30 | ## Examples
31 |
32 | ```jsx
33 | function App() {
34 | useDidMount(() => {
35 | alert("mounted");
36 | });
37 | return (
38 |
39 |
Hello CodeSandbox
40 | Start editing to see some magic happen!
41 |
42 | );
43 | }
44 | ```
45 |
46 |
47 |
48 | ## License
49 |
50 | MIT
51 |
--------------------------------------------------------------------------------
/data/docs/useArrayState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useArrayState
3 | title: useArrayState
4 | sidebar_label: useArrayState
5 | ---
6 |
7 | ## About
8 |
9 | Array state manager hook for React. It exposes push, pop, unshift, shift, concat, fill and reverse methods to be able to easily modify the state of an array.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import { useArrayState, useInput } from "rooks";
15 | export default function App() {
16 | const [array, controls] = useArrayState([1, 2, 3]);
17 | const numberInput = useInput(0);
18 |
19 | return
20 |
Array items are - {array.join(",")}
21 |
22 |
26 |
;
27 | }
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/data/docs/useAsyncEffect.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useAsyncEffect
3 | title: useAsyncEffect
4 | sidebar_label: useAsyncEffect
5 | ---
6 |
7 | ## About
8 |
9 | This is a version of `useEffect` that accepts an async function.
10 |
11 | `useEffect` only works with effect functions that run synchronously. The go-to solution for most people is to simply run an async function inside `useEffect`, but that approach has a lot of gotchas involving React state manipulation.
12 |
13 | [//]: # "Main"
14 |
15 | ## Examples
16 |
17 | ### Basic example
18 |
--------------------------------------------------------------------------------
/data/docs/useDebounce.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDebounce
3 | title: useDebounce
4 | sidebar_label: useDebounce
5 | ---
6 |
7 | ## About
8 |
9 | Debounce hook for react. Internally, it uses lodash debounce.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import React, { useState } from "react";
15 | import { useDebounce } from "rooks";
16 |
17 | export default function App() {
18 | const [value, setValue] = useState("");
19 | const setValueDebounced = useDebounce(setValue, 500);
20 |
21 | return (
22 |
23 |
setValueDebounced(e.target.value)}
25 | placeholder="Please type here"
26 | />
27 |
{value}
28 |
29 | );
30 | }
31 | ```
32 |
33 | ### Arguments
34 |
35 | | Argument | Type | Description | Default value |
36 | | -------- | -------- | ---------------------------------------- | ------------- |
37 | | callback | Function | The function to debounce | undefined |
38 | | wait | number | The duration to debounce in milliseconds | undefined |
39 | | options | Object | options to pass into lodash's debounce | {} |
40 |
41 | ### Return Value
42 |
43 | | Name | Type | Description |
44 | | ----------------- | -------- | ---------------------- |
45 | | debouncedFunction | Function | The debounced function |
46 |
--------------------------------------------------------------------------------
/data/docs/useDebounceFn.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDebounceFn
3 | title: useDebounceFn
4 | sidebar_label: useDebounceFn
5 | ---
6 |
7 | ## About
8 |
9 | Powerful debounce function hook for React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useDebounceFn} from "rooks"
15 | export default function App() {
16 | useDebounceFn();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useDeepCompareEffect.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDeepCompareEffect
3 | title: useDeepCompareEffect
4 | sidebar_label: useDeepCompareEffect
5 | ---
6 |
7 | ## About
8 |
9 | Deep compare dependencies instead of shallow for useEffect
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useDeepCompareEffect} from "rooks"
15 | export default function App() {
16 | useDeepCompareEffect();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useDidMount.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDidMount
3 | title: useDidMount
4 | sidebar_label: useDidMount
5 | ---
6 |
7 | ## About
8 |
9 | componentDidMount hook for React
10 |
11 |
12 | ## Examples
13 |
14 | ```jsx
15 | import { useDidMount } from "rooks";
16 | export default function App() {
17 | useDidMount(function() {
18 | console.log("mounted");
19 | });
20 | return null;
21 | }
22 | ```
23 |
24 | ## Arguments
25 |
26 | | Argument | Type | Description |
27 | | -------- | -------- | ------------------------------ |
28 | | callback | function | function to be called on mount |
29 |
30 | ---
31 |
--------------------------------------------------------------------------------
/data/docs/useDidUpdate.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDidUpdate
3 | title: useDidUpdate
4 | sidebar_label: useDidUpdate
5 | ---
6 |
7 | ## About
8 |
9 | componentDidUpdate hook for react
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import React, { useState } from "react";
15 | import { useDidUpdate } from "rooks";
16 |
17 | export default function App() {
18 | const [value, setValue] = useState(0);
19 | useDidUpdate(() => {
20 | console.log("This message was logged on update.");
21 | });
22 | return (
23 |
24 |
Update this value by clicking on the button
25 |
Current value is {value}
26 |
Open the sandbox in codesandbox to view the console
27 |
28 |
29 | );
30 | }
31 | ```
32 |
--------------------------------------------------------------------------------
/data/docs/useDocumentEventListener.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDocumentEventListener
3 | title: useDocumentEventListener
4 | sidebar_label: useDocumentEventListener
5 | ---
6 |
7 | ## About
8 |
9 | A react hook to an event listener to the document object
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import { useDocumentEventListener } from "rooks";
17 | import { useState, useEffect } from "react";
18 |
19 | export default function App() {
20 | const [myState, setMyState] = useState(0);
21 |
22 | useDocumentEventListener("click", function() {
23 | setMyState(myState + 1);
24 | });
25 |
26 | return (
27 |
28 |
useDocumentEventListener Example
29 |
30 | Clicked {myState} times
31 |
32 | );
33 | }
34 | ```
35 |
36 | ### Arguments
37 |
38 | | Arguments | Type | Description | Default value |
39 | | -------------- | -------- | ---------------------------------------------- | ------------- |
40 | | eventName | string | The event to track | undefind |
41 | | callback | function | The callback to be called on event | undefined |
42 | | conditions | object | The options to be passed to the event listener | {} |
43 | | isLayoutEffect | boolean | Should it use layout effect. Defaults to false | false |
44 |
45 | ### Return
46 |
47 | No return value.
48 |
--------------------------------------------------------------------------------
/data/docs/useDocumentVisibilityState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useDocumentVisibilityState
3 | title: useDocumentVisibilityState
4 | sidebar_label: useDocumentVisibilityState
5 | ---
6 |
7 | ## About
8 |
9 | Returns the visibility state of the document. Returns `null` on the server.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useEffect} from 'react'
15 | import {useDocumentVisibilityState} from "rooks"
16 |
17 | export default function App() {
18 | const isDocumentVisible = useDocumentVisibilityState();
19 | useEffect(() => {
20 | console.log(isDocumentVisible)
21 | }, [isDocumentVisible])
22 | return Try switching to a different tab and check console
23 | }
24 | ```
25 |
--------------------------------------------------------------------------------
/data/docs/useEffectOnceWhen.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useEffectOnceWhen
3 | title: useEffectOnceWhen
4 | sidebar_label: useEffectOnceWhen
5 | ---
6 |
7 | ## About
8 |
9 | Runs a callback effect atmost one time when a condition becomes true
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import { useState } from "react";
17 | import { useEffectOnceWhen } from "rooks";
18 |
19 | const App = () => {
20 | const [loading, setLoading] = useState(true);
21 |
22 | useEffectOnceWhen(() => {
23 | setTimeout(() => {
24 | setLoading(false);
25 | }, 3000); // Countdown for 3 sec
26 | }, loading);
27 |
28 | return (
29 |
30 |
Rooks: useEffectOnceWhen Example
31 |
32 |
33 |
34 | {loading
35 | ? "Loading Component (will be gone in 3 secs)...."
36 | : "Counter Component"}
37 |
38 |
39 | );
40 | };
41 |
42 | export default App;
43 | ```
44 |
45 | ### Arguments
46 |
47 | | Arguments | Type | Description | Default value |
48 | | --------- | -------- | ------------------------------------ | ------------- |
49 | | callback | function | The callback to be called | undefined |
50 | | when | boolean | The condition which needs to be true | true |
51 |
52 | ### Return
53 |
54 | No return value.
55 |
--------------------------------------------------------------------------------
/data/docs/useFileDropRef.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFileDropRef
3 | title: useFileDropRef
4 | sidebar_label: useFileDropRef
5 | ---
6 |
7 | ## About
8 |
9 | Drop files easily
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useFileDropRef } from "rooks";
15 | export default function App() {
16 | useFileDropRef();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useFocus.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFocus
3 | title: useFocus
4 | sidebar_label: useFocus
5 | ---
6 |
7 | ## About
8 |
9 | Handles focus events for the immediate target element.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useFocus } from "rooks";
15 | export default function App() {
16 | const [isFocus, setIsFocus] = useState(false);
17 | const { focusProps } = useFocus({
18 | onFocus: () => {
19 | console.log("focus");
20 | },
21 | onBlur: () => {
22 | console.log("blur");
23 | },
24 | onFocusChange: (isFocused) => {
25 | setIsFocus(isFocused);
26 | },
27 | });
28 |
29 | return (
30 |
39 | );
40 | }
41 | ```
42 |
--------------------------------------------------------------------------------
/data/docs/useFocusWithin.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFocusWithin
3 | title: useFocusWithin
4 | sidebar_label: useFocusWithin
5 | ---
6 |
7 | ## About
8 |
9 | Handles focus events for the target component.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useState } from "react";
15 | import { useFocusWithin } from "rooks";
16 |
17 | const Page = () => {
18 | const [isFocusWithin, setIsFocusWithin] = useState(false);
19 | const { focusWithinProps } = useFocusWithin({
20 | onFocusWithin: () => {
21 | console.log("focus within");
22 | },
23 | onBlurWithin: () => {
24 | console.log("blur within");
25 | },
26 | onFocusWithinChange: (isFocusWithin) => {
27 | setIsFocusWithin(isFocusWithin);
28 | },
29 | });
30 |
31 | return (
32 |
43 |
46 |
49 |
50 | );
51 | };
52 | export default Page;
53 | ```
54 |
--------------------------------------------------------------------------------
/data/docs/useFreshCallback.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFreshCallback
3 | title: useFreshCallback
4 | sidebar_label: useFreshCallback
5 | ---
6 |
7 | ## About
8 |
9 | Avoid stale closures and keep your callback fresh
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useFreshCallback} from "rooks"
15 | export default function App() {
16 | useFreshCallback();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useFreshTick.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useFreshTick
3 | title: useFreshTick
4 | sidebar_label: useFreshTick
5 | ---
6 |
7 | ## About
8 |
9 | Like useFreshRef but specifically for functions
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import { useFreshTick } from "rooks";
17 | import { useEffect, useState } from "react";
18 |
19 | /* eslint-disable */
20 |
21 | export default function App() {
22 | const [currentValue, setCurrentValue] = useState(0);
23 |
24 | function Increment() {
25 | setCurrentValue(currentValue + 1);
26 | }
27 |
28 | const freshTick = useFreshTick(Increment);
29 |
30 | useEffect(() => {
31 | const intervalId = setInterval(() => {
32 | freshTick();
33 | }, 1000);
34 | return () => clearInterval(intervalId);
35 | }, []);
36 | return (
37 |
38 |
Rooks : useFreshTick example
39 |
40 | current value : {currentValue}
41 |
42 |
43 | );
44 | }
45 | ```
46 |
47 | ### Arguments
48 |
49 | | Argument value | Type | Description |
50 | | -------------- | -------- | ------------------------------------------------------ |
51 | | callback | function | The function call which needs to be fresh at all times |
52 |
53 | ### Returns
54 |
55 | | Return value | Type | Description | Default value |
56 | | ------------ | -------- | -------------------------- | ------------- |
57 | | ref | function | A function with fresh args | undefined |
58 |
--------------------------------------------------------------------------------
/data/docs/useGetIsMounted.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useGetIsMounted
3 | title: useGetIsMounted
4 | sidebar_label: useGetIsMounted
5 | ---
6 |
7 | ## About
8 |
9 | Checks if a component is mounted or not at the time. Useful for async effects
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic usage
16 |
17 | ```jsx
18 | import { useEffect } from "react";
19 | import { useGetIsMounted } from "rooks";
20 | export default function App() {
21 | const getIsMounted = useGetIsMounted();
22 | useEffect(() => {
23 | alert("Mounted " + String(getIsMounted()));
24 | }, []);
25 | return null;
26 | }
27 | ```
28 |
--------------------------------------------------------------------------------
/data/docs/useIsDroppingFiles.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useIsDroppingFiles
3 | title: useIsDroppingFiles
4 | sidebar_label: useIsDroppingFiles
5 | ---
6 |
7 | ## About
8 |
9 | Check if any files are currently being dropped anywhere. Useful for highlighting drop areas.
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useIsDroppingFiles } from "rooks";
15 | export default function App() {
16 | useIsDroppingFiles();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useIsomorphicEffect.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useIsomorphicEffect
3 | title: useIsomorphicEffect
4 | sidebar_label: useIsomorphicEffect
5 | ---
6 |
7 | ## About
8 |
9 | A hook that resolves to useEffect on the server and useLayoutEffect on the client.
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import "./styles.css";
17 | import { useState } from "react";
18 | import { useIsomorphicEffect } from "rooks";
19 |
20 | function Component() {
21 | useIsomorphicEffect(() => {
22 | console.log("Rendered");
23 | }, []);
24 | return null;
25 | }
26 |
27 | const App = () => {
28 | const [shouldRender, enableRender] = useState(true);
29 | return (
30 |
31 |
Rook: useIsomorphicEffect Example
32 |
33 |
34 |
41 |
42 |
43 |
Explore console
44 | {shouldRender &&
}
45 |
46 |
47 | );
48 | };
49 |
50 | export default App;
51 | ```
52 |
53 | ### Arguments
54 |
55 | | Argument value | Type | Description |
56 | | -------------- | -------- | --------------------------------------- |
57 | | callback | function | Callback function to be called on mount |
58 |
59 | ### Returns
60 |
61 | Returns `useEffect` when "window" is not in scope and `useLayoutEffect` in the browser
62 |
--------------------------------------------------------------------------------
/data/docs/useKeyBindings.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useKeyBindings
3 | title: useKeyBindings
4 | sidebar_label: useKeyBindings
5 | ---
6 |
7 | ## About
8 |
9 | useKeyBindings can bind pairs of keyboard events and handlers.
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import "./styles.css";
17 | import { useKeyBindings, useCounter } from "rooks";
18 |
19 | export default function App() {
20 | const { value, increment, incrementBy, decrementBy, reset } = useCounter(0);
21 | const cb1 = () => increment();
22 | const cb2 = () => decrementBy(3);
23 | const cb3 = () => incrementBy(5);
24 | const cb4 = () => reset();
25 |
26 | useKeyBindings({ a: cb1, b: cb2, Enter: cb3, Escape: cb4 });
27 |
28 | return (
29 |
30 |
31 | Counter value is : {value}
32 |
33 |
34 | );
35 | }
36 | ```
37 |
38 | ### Arguments
39 |
40 | | Argument | Type | Description | Default value |
41 | | ----------- | ------- | ------------------------------------- | ------------- |
42 | | keyBindings | Object | pairs of keyboard events and handlers | {} |
43 | | options | Options | refer to useKey | {} |
44 |
--------------------------------------------------------------------------------
/data/docs/useLifecycleLogger.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useLifecycleLogger
3 | title: useLifecycleLogger
4 | sidebar_label: useLifecycleLogger
5 | ---
6 |
7 | ## About
8 |
9 | A react hook that console logs parameters as component transitions through lifecycles.
10 |
11 | [//]: # "Main"
12 |
13 | ## Installation
14 |
15 | ## Examples
16 |
17 | ```jsx
18 | import "./styles.css";
19 | import { useLifecycleLogger } from "rooks";
20 | import { useEffect, useState } from "react";
21 |
22 | export default function App() {
23 | const [value, setValue] = useState(0);
24 |
25 | useEffect(() => {
26 | setValue(1);
27 | }, []);
28 |
29 | useLifecycleLogger("Demo", value);
30 |
31 | return (
32 |
33 |
useLifecycleLogger example
34 | See console for logs
35 |
36 | );
37 | }
38 | ```
39 |
40 | ### Arguments
41 |
42 | | Argument value | Type | Description | Defualt |
43 | | -------------- | ------ | -------------------------------------------------------- | ----------- |
44 | | componentName | String | The name of component to be shown in the log | "Component" |
45 | | rest | Array | An arry of variables to be logged in component lifecycle | undefined |
46 |
47 | ### Returns
48 |
49 | No return value
50 |
--------------------------------------------------------------------------------
/data/docs/useLockBodyScroll.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useLockBodyScroll
3 | title: useLockBodyScroll
4 | sidebar_label: useLockBodyScroll
5 | ---
6 |
7 | ## About
8 |
9 | Locks or unlocks body scroll
10 |
11 | ## Examples
12 |
13 | ### Basic
14 |
15 | ```tsx
16 | import { useState } from "react";
17 | import { useLockBodyScroll } from "rooks";
18 |
19 | export default function App() {
20 | const [isLocked, setIsLocked] = useState(false);
21 |
22 | // Lock body scroll when isLocked is true
23 | useLockBodyScroll(isLocked);
24 |
25 | return (
26 |
27 |
30 |
31 | );
32 | }
33 | ```
34 |
35 | ## Arguments
36 |
37 | | Argument | Type | Description |
38 | | -------- | ------- | ------------------------------------------------ |
39 | | isLocked | boolean | Whether to lock or unlock scroll on the body tag |
40 |
41 | ---
42 |
--------------------------------------------------------------------------------
/data/docs/useMergeRefs.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMergeRefs
3 | title: useMergeRefs
4 | sidebar_label: useMergeRefs
5 | ---
6 |
7 | ## About
8 |
9 | Merges any number of refs into a single ref
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import "./styles.css";
17 | import { useMergeRefs, useEventListenerRef } from "rooks";
18 |
19 | function App() {
20 | const mousedownRef = useEventListenerRef("mousedown", () => {
21 | console.log("mouse down");
22 | });
23 | const mouseupRef = useEventListenerRef("mouseup", () => {
24 | console.log("mouse up");
25 | });
26 | const refs = useMergeRefs(mousedownRef, mouseupRef);
27 |
28 | return (
29 |
30 |
Rooks : useMergeRefs Example
31 |
32 |
40 | A div with multiple refs. Click me!!
41 |
42 |
43 | );
44 | }
45 | export default App;
46 | ```
47 |
48 | ### Arguments
49 |
50 | | Argument value | Type | Description |
51 | | -------------- | ----- | -------------------------------------------------------------------- |
52 | | refs | Array | Takes any number of refs. Refs can be mutable refs or function refs. |
53 |
54 | ### Returns
55 |
56 | | Return value | Type | Description |
57 | | ------------ | ----------- | ----------- |
58 | | ref | CallbackRef | Merged ref |
59 |
--------------------------------------------------------------------------------
/data/docs/useMouse.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMouse
3 | title: useMouse
4 | sidebar_label: useMouse
5 | ---
6 |
7 | ## About
8 |
9 | ### Description
10 |
11 | Mouse position hook for React.
12 |
13 |
14 | ### Return value
15 |
16 | useMouse returns a single object containing the mouse position.
17 |
18 | | Returned object attributes | Type | Description |
19 | | -------------------------- | ---- | ------------------- |
20 | | x | int | X position of mouse |
21 | | y | int | Y position of mouse |
22 |
23 |
24 | ## Examples
25 | ### Basic Usage
26 |
27 | ```jsx
28 | import { useMouse } from "rooks";
29 |
30 | export default function App() {
31 | const { x, y } = useMouse();
32 | return (
33 | <>
34 | Move mouse here to see changes to position
35 | X position is {x || "null"}
36 | X position is {y || "null"}
37 | >
38 | );
39 | }
40 | ```
41 |
42 |
43 |
--------------------------------------------------------------------------------
/data/docs/useMouseMoveDelta.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMouseMoveDelta
3 | title: useMouseMoveDelta
4 | sidebar_label: useMouseMoveDelta
5 | ---
6 |
7 | ## About
8 |
9 | Tracks delta of mouse move
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useMouseMoveDelta} from "rooks"
15 | export default function App() {
16 | useMouseMoveDelta();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useMouseWheelDelta.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useMouseWheelDelta
3 | title: useMouseWheelDelta
4 | sidebar_label: useMouseWheelDelta
5 | ---
6 |
7 | ## About
8 |
9 | Tracks delta of mouse move
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useMouseWheelDelta} from "rooks"
15 | export default function App() {
16 | useMouseWheelDelta();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useNativeMapState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useNativeMapState
3 | title: useNativeMapState
4 | sidebar_label: useNativeMapState
5 | ---
6 |
7 | ## About
8 |
9 | Manage Map() object state in React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useNativeMapState } from "rooks";
15 | export default function App() {
16 | useNativeMapState();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useNavigatorLanguage.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useNavigatorLanguage
3 | title: useNavigatorLanguage
4 | sidebar_label: useNavigatorLanguage
5 | ---
6 |
7 | ## About
8 |
9 | Navigator Language hook for React.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useNavigatorLanguage } from "rooks";
16 |
17 | function App() {
18 | const language = useNavigatorLanguage();
19 |
20 | return (
21 |
24 |
Rooks : useNavigatorLanguage example
25 |
26 | Language is {language}
27 |
28 |
29 | );
30 | }
31 |
32 | export default App;
33 | ```
34 |
35 | ### Return value
36 |
37 | A language (String) is returned.
38 |
--------------------------------------------------------------------------------
/data/docs/useOnClickRef.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnClickRef
3 | title: useOnClickRef
4 | sidebar_label: useOnClickRef
5 | ---
6 |
7 | ## About
8 |
9 | Callback on click/tap events
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import { useOnClickRef } from "rooks";
15 | export default function App() {
16 | useOnClickRef();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useOnHoverRef.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnHoverRef
3 | title: useOnHoverRef
4 | sidebar_label: useOnHoverRef
5 | ---
6 |
7 | ## About
8 |
9 | On hover callback hook
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useOnHoverRef} from "rooks"
15 | export default function App() {
16 | useOnHoverRef();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useOnWindowResize.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnWindowResize
3 | title: useOnWindowResize
4 | sidebar_label: useOnWindowResize
5 | ---
6 |
7 | ## About
8 |
9 | A React hook for adding an event listener for window resize
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useOnWindowResize } from "rooks";
16 |
17 | export default function App() {
18 | useOnWindowResize(() => console.log("window resized"));
19 |
20 | return (
21 |
22 |
useOnWindowResize example
23 | Resize the window and see the logs
24 |
25 | );
26 | }
27 | ```
28 |
29 | ### Arguments
30 |
31 | | Arguments | Type | Description | Default value |
32 | | -------------- | -------- | ----------------------------------------------- | ------------- |
33 | | callback | function | Callback function which needs to run on unmount | undefined |
34 | | when | boolean | When the event handler should be active | true |
35 | | isLayoutEffect | boolean | Should it use layout effect. | false |
36 |
37 | ### Returns
38 |
39 | No return value.
40 |
--------------------------------------------------------------------------------
/data/docs/useOnline.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOnline
3 | title: useOnline
4 | sidebar_label: useOnline
5 | ---
6 |
7 | ## About
8 |
9 | Online status hook for React.
10 |
11 | ### Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useOnline } from "rooks";
16 |
17 | function App() {
18 | const online = useOnline();
19 | console.log("I'm online");
20 |
21 | return (
22 |
23 |
Rooks: useOnline example
24 |
25 |
26 |
27 | Status:You are {online ? "Online" : "Offline"}
28 |
29 |
30 | );
31 | }
32 |
33 | export default App;
34 | ```
35 |
36 | ### Return value
37 |
38 | Offline status (boolean) is returned.
39 |
--------------------------------------------------------------------------------
/data/docs/useOrientation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useOrientation
3 | title: useOrientation
4 | sidebar_label: useOrientation
5 | ---
6 |
7 | ## About
8 |
9 | orientation hook for react
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useOrientation} from "rooks"
15 | export default function App() {
16 | useOrientation();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/usePromise.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: usePromise
3 | title: usePromise
4 | sidebar_label: usePromise
5 | ---
6 |
7 | ## About
8 |
9 | Promise management hook for react
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {usePromise} from "rooks"
15 | export default function App() {
16 | usePromise();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useRenderCount.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useRenderCount
3 | title: useRenderCount
4 | sidebar_label: useRenderCount
5 | ---
6 |
7 | ## About
8 |
9 | Get the render count of a component
10 |
11 | ## Examples
12 |
13 | TODO: Add an example here.
14 |
--------------------------------------------------------------------------------
/data/docs/useSafeSetState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSafeSetState
3 | title: useSafeSetState
4 | sidebar_label: useSafeSetState
5 | ---
6 |
7 | ## About
8 |
9 | set state but ignores if component has already unmounted
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useSafeSetState} from "rooks"
15 | export default function App() {
16 | useSafeSetState();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useSessionstorageState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSessionstorageState
3 | title: useSessionstorageState
4 | sidebar_label: useSessionstorageState
5 | ---
6 |
7 | ## About
8 |
9 | useState but syncs with sessionstorage
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ```jsx
16 | import "./styles.css";
17 | import React from "react";
18 | import { useSessionstorageState } from "rooks";
19 |
20 | export default function App() {
21 | const [count, setCount] = useSessionstorageState("my-app:count", 0);
22 |
23 | return (
24 |
25 |
Rooks : useSessionstorageState
26 |
Refresh the page to see the previous value in tact
27 |
28 |
29 |
30 | );
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/data/docs/useSetState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSetState
3 | title: useSetState
4 | sidebar_label: useSetState
5 | ---
6 |
7 | ## About
8 |
9 | Manage the state of a Set in React. Exposes add, delete and clear methods along with the current set to easily manipulate values in a set.
10 |
11 | ## Examples
12 |
13 | ```jsx
14 | import { useSetState } from "rooks";
15 | export default function App() {
16 | useSetState();
17 | return null;
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useSpeech.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useSpeech
3 | title: useSpeech
4 | sidebar_label: useSpeech
5 | ---
6 |
7 | ## About
8 |
9 | Speech synthesis hook for React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useSpeech} from "rooks"
15 | export default function App() {
16 | useSpeech();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useTimeTravelState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useTimeTravelState
3 | title: useTimeTravelState
4 | sidebar_label: useTimeTravelState
5 | ---
6 |
7 | ## About
8 |
9 | A hook that manages state which can undo and redo. A more powerful version of useUndoState hook.
10 |
11 | ## Examples
12 |
13 | ### Basic example
14 |
15 | ```tsx
16 | import { useTimeTravelState } from "rooks";
17 | export default function App() {
18 | const [value, setValue, controls] = useTimeTravelState(0);
19 |
20 | return (
21 |
22 |
Current value: {value}
23 |
24 |
25 | Can undo: {String(controls.canUndo)}
26 | Can redo: {String(controls.canRedo)}
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/data/docs/useTimeoutWhen.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useTimeoutWhen
3 | title: useTimeoutWhen
4 | sidebar_label: useTimeoutWhen
5 | ---
6 |
7 | ## About
8 |
9 | Takes a callback and fires it when a condition is true
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic usage
16 |
17 | ```jsx
18 | import "./styles.css";
19 | import { useTimeoutWhen } from "rooks";
20 | import { useState } from "react";
21 |
22 | function App() {
23 | const [start, setStart] = useState(false);
24 | useTimeoutWhen(() => setStart(false), 2000, start);
25 | return (
26 | <>
27 | Rooks: useTimeoutWhen example
28 |
29 | Click the button below to disable it for 2 seconds
30 |
33 | >
34 | );
35 | }
36 |
37 | export default App;
38 | ```
39 |
40 | ### Arguments
41 |
42 | | Arguments | Type | Description | Default value |
43 | | --------- | -------- | -------------------------------------------------------- | ------------- |
44 | | callback | function | Function to be executed in timeout | undefind |
45 | | delay | Number | Number in milliseconds after which callback is to be run | 0 |
46 | | when | boolean | The condition which when true, sets the timeout | true |
47 |
48 | ### Returned
49 |
50 | No return value.
51 |
--------------------------------------------------------------------------------
/data/docs/useUndoRedoState.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useUndoRedoState
3 | title: useUndoRedoState
4 | sidebar_label: useUndoRedoState
5 | ---
6 |
7 | ## About
8 |
9 | Setstate but can also undo and redo
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useUndoRedoState} from "rooks"
15 | export default function App() {
16 | useUndoRedoState();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useVibrate.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useVibrate
3 | title: useVibrate
4 | sidebar_label: useVibrate
5 | ---
6 |
7 | ## About
8 |
9 | Vibration API hook for React
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useVibrate} from "rooks"
15 | export default function App() {
16 | useVibrate();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useVideo.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useVideo
3 | title: useVideo
4 | sidebar_label: useVideo
5 | ---
6 |
7 | ## About
8 |
9 | Video hook for react
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useVideo} from "rooks"
15 | export default function App() {
16 | useVideo();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useWhyDidYouUpdate.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWhyDidYouUpdate
3 | title: useWhyDidYouUpdate
4 | sidebar_label: useWhyDidYouUpdate
5 | ---
6 |
7 | ## About
8 |
9 | A hook that can track which value change caused a rerender
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {useWhyDidYouUpdate} from "rooks"
15 | export default function App() {
16 | useWhyDidYouUpdate();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/data/docs/useWillUnmount.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWillUnmount
3 | title: useWillUnmount
4 | sidebar_label: useWillUnmount
5 | ---
6 |
7 | ### About
8 |
9 | A React hook for componentWillUnmount lifecycle method.
10 |
11 | ### Examples
12 |
13 | ```jsx
14 | import "./styles.css";
15 | import { useState } from "react";
16 | import { useWillUnmount } from "rooks";
17 |
18 | function Message() {
19 | useWillUnmount(function(props) {
20 | console.log("UNMOUNT", props);
21 | });
22 | return This component will unmount
;
23 | }
24 |
25 | const App = () => {
26 | const [shouldRender, enableRender] = useState(true);
27 | return (
28 |
29 |
Rook: useWillUnmount Example
30 |
31 |
32 |
39 |
40 |
Check or Uncheck the box
41 |
enableRender(!shouldRender)} type="checkBox" />
42 |
43 | {shouldRender &&
}
44 |
45 |
46 | );
47 | };
48 |
49 | export default App;
50 | ```
51 |
52 | #### Arguments
53 |
54 | | Arguments | Type | Description | Default value |
55 | | --------- | -------- | ----------------------------------------------- | ------------- |
56 | | callback | function | Callback function which needs to run on unmount | undefined |
57 |
--------------------------------------------------------------------------------
/data/docs/useWindowEventListener.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWindowEventListener
3 | title: useWindowEventListener
4 | sidebar_label: useWindowEventListener
5 | ---
6 |
7 | ## About
8 |
9 | Adds an event listener to window
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic usage
16 |
17 | ```jsx
18 | import { useState } from "react";
19 | import { useWindowEventListener } from "rooks";
20 | import "./styles.css";
21 |
22 | export default function App() {
23 | const [value, setValue] = useState(0);
24 | useWindowEventListener("click", function() {
25 | setValue(value + 1);
26 | });
27 | return (
28 |
34 |
Click anywhere
35 |
Value is {value}
36 |
37 | );
38 | }
39 | ```
40 |
41 | ---
42 |
--------------------------------------------------------------------------------
/data/docs/useWindowScrollPosition.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: useWindowScrollPosition
3 | title: useWindowScrollPosition
4 | sidebar_label: useWindowScrollPosition
5 | ---
6 |
7 | ## About
8 |
9 | A React hook to get the scroll position of the window
10 |
11 | [//]: # "Main"
12 |
13 | ## Examples
14 |
15 | ### Basic Usage
16 |
17 | ```jsx
18 | import "./styles.css";
19 | import { useWindowScrollPosition } from "rooks";
20 |
21 | function App() {
22 | const position = useWindowScrollPosition(); // default config: { wait = 100, passive = true }
23 | console.log(position); // {x: ..., y: ...}
24 | return (
25 |
26 |
Rooks : useWindowScrollPosition Example
27 |
28 |
29 |
Scroll
30 |
{JSON.stringify(position)}
31 |
32 | );
33 | }
34 |
35 | export default App;
36 | ```
37 |
--------------------------------------------------------------------------------
/i18n/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "_comment": "This file is auto-generated by write-translations.js",
3 | "localized-strings": {
4 | "next": "Next",
5 | "previous": "Previous",
6 | "tagline": "Commonly used hooks for everyone",
7 | "docs": {},
8 | "links": {},
9 | "categories": {
10 | "Guides": "Guides",
11 | "General": "General"
12 | }
13 | },
14 | "pages-strings": {
15 | "Help Translate|recruit community translators for your project": "Help Translate",
16 | "Edit this Doc|recruitment message asking to edit the doc source": "Edit",
17 | "Translate this Doc|recruitment message asking to translate the docs": "Translate"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/eslint-config/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @repo/eslint-config
2 |
3 | ## 0.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [#1774](https://github.com/imbhargav5/rooks/pull/1774) [`3714495`](https://github.com/imbhargav5/rooks/commit/37144959801a8c71ca9757b01656190c1ffe1218) Thanks [@imbhargav5](https://github.com/imbhargav5)! - upgrade to react 19
8 |
--------------------------------------------------------------------------------
/packages/eslint-config/README.md:
--------------------------------------------------------------------------------
1 | # `@turbo/eslint-config`
2 |
3 | Collection of internal eslint configurations.
4 |
--------------------------------------------------------------------------------
/packages/eslint-config/base.js:
--------------------------------------------------------------------------------
1 | import js from "@eslint/js";
2 | import eslintConfigPrettier from "eslint-config-prettier";
3 | import turboPlugin from "eslint-plugin-turbo";
4 | import tseslint from "typescript-eslint";
5 | import onlyWarn from "eslint-plugin-only-warn";
6 |
7 | /**
8 | * A shared ESLint configuration for the repository.
9 | *
10 | * @type {import("eslint").Linter.Config}
11 | * */
12 | export const config = [
13 | js.configs.recommended,
14 | eslintConfigPrettier,
15 | ...tseslint.configs.recommended,
16 | {
17 | plugins: {
18 | turbo: turboPlugin,
19 | },
20 | rules: {
21 | "turbo/no-undeclared-env-vars": "warn",
22 | },
23 | },
24 | {
25 | plugins: {
26 | onlyWarn,
27 | },
28 | },
29 | {
30 | ignores: ["dist/**"],
31 | },
32 | ];
33 |
--------------------------------------------------------------------------------
/packages/eslint-config/next.js:
--------------------------------------------------------------------------------
1 | import js from "@eslint/js";
2 | import eslintConfigPrettier from "eslint-config-prettier";
3 | import tseslint from "typescript-eslint";
4 | import pluginReactHooks from "eslint-plugin-react-hooks";
5 | import pluginReact from "eslint-plugin-react";
6 | import globals from "globals";
7 | import pluginNext from "@next/eslint-plugin-next";
8 | import { config as baseConfig } from "./base.js";
9 |
10 | /**
11 | * A custom ESLint configuration for libraries that use Next.js.
12 | *
13 | * @type {import("eslint").Linter.Config}
14 | * */
15 | export const nextJsConfig = [
16 | ...baseConfig,
17 | js.configs.recommended,
18 | eslintConfigPrettier,
19 | ...tseslint.configs.recommended,
20 | {
21 | ...pluginReact.configs.flat.recommended,
22 | languageOptions: {
23 | ...pluginReact.configs.flat.recommended.languageOptions,
24 | globals: {
25 | ...globals.serviceworker,
26 | },
27 | },
28 | },
29 | {
30 | plugins: {
31 | "@next/next": pluginNext,
32 | },
33 | rules: {
34 | ...pluginNext.configs.recommended.rules,
35 | ...pluginNext.configs["core-web-vitals"].rules,
36 | },
37 | },
38 | {
39 | plugins: {
40 | "react-hooks": pluginReactHooks,
41 | },
42 | settings: { react: { version: "detect" } },
43 | rules: {
44 | ...pluginReactHooks.configs.recommended.rules,
45 | // React scope no longer necessary with new JSX transform.
46 | "react/react-in-jsx-scope": "off",
47 | },
48 | },
49 | ];
50 |
--------------------------------------------------------------------------------
/packages/eslint-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@repo/eslint-config",
3 | "version": "0.1.0",
4 | "type": "module",
5 | "private": true,
6 | "exports": {
7 | "./base": "./base.js",
8 | "./next-js": "./next.js",
9 | "./react-internal": "./react-internal.js"
10 | },
11 | "devDependencies": {
12 | "@eslint/js": "^9.22.0",
13 | "@next/eslint-plugin-next": "^15.2.1",
14 | "eslint": "^9.22.0",
15 | "eslint-config-prettier": "^10.1.1",
16 | "eslint-plugin-only-warn": "^1.1.0",
17 | "eslint-plugin-react": "^7.37.4",
18 | "eslint-plugin-react-hooks": "^5.2.0",
19 | "eslint-plugin-turbo": "^2.4.4",
20 | "globals": "^16.0.0",
21 | "typescript": "^5.8.2",
22 | "typescript-eslint": "^8.26.0"
23 | }
24 | }
--------------------------------------------------------------------------------
/packages/eslint-config/react-internal.js:
--------------------------------------------------------------------------------
1 | import js from "@eslint/js";
2 | import eslintConfigPrettier from "eslint-config-prettier";
3 | import tseslint from "typescript-eslint";
4 | import pluginReactHooks from "eslint-plugin-react-hooks";
5 | import pluginReact from "eslint-plugin-react";
6 | import globals from "globals";
7 | import { config as baseConfig } from "./base.js";
8 |
9 | /**
10 | * A custom ESLint configuration for libraries that use React.
11 | *
12 | * @type {import("eslint").Linter.Config} */
13 | export const config = [
14 | ...baseConfig,
15 | js.configs.recommended,
16 | eslintConfigPrettier,
17 | ...tseslint.configs.recommended,
18 | pluginReact.configs.flat.recommended,
19 | {
20 | languageOptions: {
21 | ...pluginReact.configs.flat.recommended.languageOptions,
22 | globals: {
23 | ...globals.serviceworker,
24 | ...globals.browser,
25 | },
26 | },
27 | },
28 | {
29 | plugins: {
30 | "react-hooks": pluginReactHooks,
31 | },
32 | settings: { react: { version: "detect" } },
33 | rules: {
34 | ...pluginReactHooks.configs.recommended.rules,
35 | // React scope no longer necessary with new JSX transform.
36 | "react/react-in-jsx-scope": "off",
37 | },
38 | },
39 | ];
40 |
--------------------------------------------------------------------------------
/packages/rooks/.escheckrc:
--------------------------------------------------------------------------------
1 | {
2 | "ecmaVersion": "es2017",
3 | "module": true,
4 | "files": "./dist/esm/**/*.js"
5 | }
--------------------------------------------------------------------------------
/packages/rooks/.gitignore:
--------------------------------------------------------------------------------
1 | .vercel
2 | node_modules/
3 | /test-results/
4 | /playwright-report/
5 | /playwright/.cache/
6 | /test-results/
7 | /playwright-report/
8 | /playwright/.cache/
9 |
--------------------------------------------------------------------------------
/packages/rooks/.npmignore:
--------------------------------------------------------------------------------
1 | *
2 | !dist/**/*
3 | dist/esm/__tests__
4 | dist/cjs/__tests__
5 | dist/umd/__tests__
6 | !CHANGELOG.md
7 | !README.md
8 | !LICENSE
9 |
--------------------------------------------------------------------------------
/packages/rooks/.size-limit.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | // Regularly update this max size when new hooks are added (keep a threshold)
4 | const fullBundleMaxSize = "20KB";
5 |
6 | /**
7 | * Will ensure esm tree-shakeability and total size are within expectations.
8 | *
9 | * @link https://github.com/ai/size-limit/
10 | * @type {{name: string, path: string[], limit: string, import?: string, webpack?: boolean}[]}
11 | */
12 | module.exports = [
13 | // Size of all imports from the esm bundle
14 | {
15 | name: "ESM Webpack (*)",
16 | webpack: true,
17 | path: ["dist/esm/index.js"],
18 | import: "*",
19 | limit: fullBundleMaxSize,
20 | },
21 | // Size of an individual import from the esm bundle
22 | // We can also do this eventually if we want
23 | // {
24 | // name: "ESM Webpack ({ useDebounce })",
25 | // webpack: true,
26 | // path: ["dist/esm/index.js"],
27 | // import: "{ useDebounce }",
28 | // limit: "2KB",
29 | // },
30 | {
31 | name: "CJS Webpack (*)",
32 | path: ["dist/cjs/index.js"],
33 | webpack: true,
34 | import: "*", // CJS does not tree-shake in webpack5.
35 | limit: fullBundleMaxSize,
36 | },
37 | {
38 | name: "UMD bundle size (*)",
39 | path: ["dist/umd/rooks.umd.js"],
40 | webpack: false,
41 | limit: fullBundleMaxSize,
42 | },
43 | ];
44 |
--------------------------------------------------------------------------------
/packages/rooks/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { config } from "@repo/eslint-config/react-internal";
2 |
3 | /** @type {import("eslint").Linter.Config} */
4 | export default config;
5 |
--------------------------------------------------------------------------------
/packages/rooks/jest.config.ts:
--------------------------------------------------------------------------------
1 | // jest.config.ts
2 | import type { JestConfigWithTsJest } from 'ts-jest';
3 | import { readFileSync } from 'fs';
4 | import { join } from 'path';
5 |
6 | // Read tsconfig.json file and parse it to get paths
7 | const tsConfigPath = join(__dirname, 'tsconfig.json');
8 | const tsConfig = JSON.parse(readFileSync(tsConfigPath, 'utf8'));
9 |
10 | const config: JestConfigWithTsJest = {
11 | preset: 'ts-jest',
12 | testEnvironment: 'jsdom',
13 | testMatch: ['/src/__tests__/**/*.(spec|test).(ts|tsx)'],
14 | verbose: true,
15 | transform: {
16 | '^.+\\.[jt]sx?$': 'esbuild-jest',
17 | },
18 | moduleNameMapper: {
19 | // Map paths from tsconfig
20 | '@/(.*)$': '/src/$1',
21 | },
22 | rootDir: '.',
23 | coverageProvider: 'v8',
24 | modulePaths: ['/src'],
25 | setupFilesAfterEnv: ['/src/jest.setup.ts'],
26 | };
27 |
28 | export default config;
29 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/ErrorBoundary.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode } from "react";
2 |
3 | type Props = Readonly<{ [key: string]: unknown } & { children: ReactNode }>;
4 |
5 | export class ErrorBoundary extends React.Component<
6 | Props,
7 | {
8 | error: Error | null;
9 | }
10 | > {
11 | constructor(props: Props) {
12 | super(props);
13 | this.state = { error: null };
14 | }
15 |
16 | static getDerivedStateFromError(error: Error) {
17 | // Update state so the next render will show the fallback UI.
18 | return { error: error };
19 | }
20 |
21 | componentDidCatch(error: Error) {
22 | console.log("caught error", error.message);
23 | }
24 |
25 | render() {
26 | if (this.state.error) {
27 | return {this.state.error.message}
;
28 | }
29 |
30 | return this.props.children;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useAudio.spec.tsx:
--------------------------------------------------------------------------------
1 | import { useAudio } from "@/hooks/useAudio";
2 |
3 | // write a simple test which checks if useAudio is defined
4 | describe("useAudio", () => {
5 | it("is defined", () => {
6 | expect.hasAssertions();
7 | expect(useAudio).not.toBeUndefined();
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useDidMount.spec.ts:
--------------------------------------------------------------------------------
1 | import { renderHook } from "@testing-library/react-hooks";
2 | import { useState } from "react";
3 | import { useDidMount } from "@/hooks/useDidMount";
4 |
5 | describe("useDidMount", () => {
6 | it("is defined", () => {
7 | expect.hasAssertions();
8 | expect(useDidMount).toBeDefined();
9 | });
10 | describe("base", () => {
11 | let useHook = () => {
12 | return {
13 | value: 0,
14 | };
15 | };
16 |
17 | beforeEach(() => {
18 | useHook = function () {
19 | const [value, setValue] = useState(0);
20 | useDidMount(() => {
21 | setValue(9_000);
22 | });
23 |
24 | return { value };
25 | };
26 | });
27 | it("runs immediately after mount", async () => {
28 | expect.hasAssertions();
29 | const { result } = renderHook(() => useHook());
30 | expect(result.current.value).toBe(9_000);
31 | });
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useDocumentVisibilityState.spec.ts:
--------------------------------------------------------------------------------
1 | import { useDocumentVisibilityState } from "@/hooks/useDocumentVisibilityState";
2 |
3 | describe("useDocumentVisibilityState", () => {
4 | it("should be defined", () => {
5 | expect.hasAssertions();
6 | expect(useDocumentVisibilityState).toBeDefined();
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useForkRef.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, getByTestId, fireEvent } from "@testing-library/react";
3 |
4 | import TestRenderer from "react-test-renderer";
5 | import { useEventListenerRef } from "@/hooks/useEventListenerRef";
6 | import { useForkRef } from "@/hooks/useForkRef";
7 |
8 | const { act } = TestRenderer;
9 |
10 | describe("useForkRef", () => {
11 | let mockCallback = () => {};
12 | let TestJSX = () => ;
13 | beforeEach(() => {
14 | mockCallback = jest.fn(() => {});
15 | TestJSX = () => {
16 | const mouseUpRef = useEventListenerRef("mouseup", mockCallback);
17 | const mouseDownRef = useEventListenerRef("mousedown", mockCallback);
18 | const ref = useForkRef(mouseUpRef, mouseDownRef);
19 |
20 | return (
21 |
22 | Click me
23 |
24 | );
25 | };
26 | });
27 |
28 | it("should be defined", () => {
29 | expect.hasAssertions();
30 | expect(useForkRef).toBeDefined();
31 | });
32 |
33 | it("should be called on mouse events", () => {
34 | expect.hasAssertions();
35 | const { container } = render();
36 | const displayElement = getByTestId(container as HTMLElement, "element");
37 | act(() => {
38 | fireEvent.mouseUp(displayElement);
39 | fireEvent.mouseDown(displayElement);
40 | });
41 | expect(mockCallback).toHaveBeenCalledTimes(2);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useFreshCallback.spec.ts:
--------------------------------------------------------------------------------
1 | import { useFreshCallback } from "@/hooks/useFreshCallback";
2 |
3 | describe("useFreshCallback", () => {
4 | it("should be defined", () => {
5 | expect.hasAssertions();
6 | expect(useFreshCallback).toBeDefined();
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useGetIsMounted.spec.ts:
--------------------------------------------------------------------------------
1 | import { renderHook } from "@testing-library/react-hooks";
2 | import { useGetIsMounted } from "@/hooks/useGetIsMounted";
3 |
4 | describe("useGetIsMounted", () => {
5 | it("should be defined", () => {
6 | expect.hasAssertions();
7 | expect(useGetIsMounted).toBeDefined();
8 | });
9 |
10 | it("should return a function", () => {
11 | expect.hasAssertions();
12 | const hook = renderHook(() => useGetIsMounted());
13 |
14 | expect(typeof hook.result.current).toBe("function");
15 | });
16 |
17 | it("should return true if component is mounted", () => {
18 | expect.hasAssertions();
19 | const hook = renderHook(() => useGetIsMounted());
20 |
21 | expect(hook.result.current()).toBe(true);
22 | });
23 |
24 | it("should return false if component is unmounted", () => {
25 | expect.hasAssertions();
26 | const hook = renderHook(() => useGetIsMounted());
27 |
28 | hook.unmount();
29 |
30 | expect(hook.result.current()).toBe(false);
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useLockBodyScroll.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, screen, fireEvent, act } from "@testing-library/react";
3 | import { useState } from "react";
4 | import { useLockBodyScroll } from "@/hooks/useLockBodyScroll";
5 |
6 | function ExampleComponent() {
7 | const [isLocked, setIsLocked] = useState(false);
8 |
9 | // Lock body scroll when isLocked is true
10 | useLockBodyScroll(isLocked);
11 |
12 | return (
13 |
14 |
17 |
18 | );
19 | }
20 |
21 | describe("useLockBodyScroll", () => {
22 | test("lock and unlock body scroll", () => {
23 | expect.hasAssertions();
24 | render();
25 |
26 | const button = screen.getByText("Lock scroll");
27 |
28 | // Check if the body scroll is initially unlocked
29 | expect(document.body.style.overflow).toBe("");
30 |
31 | // Lock the body scroll
32 | act(() => {
33 | fireEvent.click(button);
34 | });
35 | expect(document.body.style.overflow).toBe("hidden");
36 | expect(button.textContent).toBe("Unlock scroll");
37 |
38 | // Unlock the body scroll
39 | act(() => {
40 | fireEvent.click(button);
41 | });
42 | expect(document.body.style.overflow).toBe("");
43 | expect(button.textContent).toBe("Lock scroll");
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useNavigatorLanguage.spec.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment jsdom
3 | */
4 | import { renderHook } from "@testing-library/react-hooks";
5 | import { useNavigatorLanguage } from "@/hooks/useNavigatorLanguage";
6 |
7 | describe("useNavigatorLanguage", () => {
8 | let languageGetter = jest.spyOn(window.navigator, "language", "get");
9 |
10 | beforeEach(() => {
11 | languageGetter = jest.spyOn(window.navigator, "language", "get");
12 | });
13 |
14 | it("should be defined", () => {
15 | expect.hasAssertions();
16 | expect(useNavigatorLanguage).toBeDefined();
17 | });
18 |
19 | it("should get the navigator language", () => {
20 | expect.hasAssertions();
21 | languageGetter.mockReturnValue("de");
22 | const { result } = renderHook(() => useNavigatorLanguage());
23 | expect(result.current).toBe("de");
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useOnWindowResize.spec.ts:
--------------------------------------------------------------------------------
1 | import { fireEvent } from "@testing-library/react";
2 | import { renderHook } from "@testing-library/react-hooks";
3 | import { useOnWindowResize } from "@/hooks/useOnWindowResize";
4 |
5 | describe("useOnWindowResize", () => {
6 | it("should be defined", () => {
7 | expect.hasAssertions();
8 | expect(useOnWindowResize).toBeDefined();
9 | });
10 |
11 | describe("basic", () => {
12 | const mockCallback = jest.fn(() => {});
13 | it("should call callback after resize", () => {
14 | expect.hasAssertions();
15 | renderHook(() => useOnWindowResize(mockCallback));
16 | fireEvent(window, new Event("resize"));
17 | expect(mockCallback.mock.calls).toHaveLength(1);
18 | fireEvent(window, new Event("resize"));
19 | fireEvent(window, new Event("resize"));
20 | expect(mockCallback.mock.calls).toHaveLength(3);
21 | });
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useOnWindowScroll.spec.ts:
--------------------------------------------------------------------------------
1 | import { fireEvent } from "@testing-library/react";
2 | import { renderHook } from "@testing-library/react-hooks";
3 | import { useOnWindowScroll } from "@/hooks/useOnWindowScroll";
4 |
5 | describe("useOnWindowScroll", () => {
6 | it("should be defined", () => {
7 | expect.hasAssertions();
8 | expect(useOnWindowScroll).toBeDefined();
9 | });
10 |
11 | describe("basic", () => {
12 | const mockCallback = jest.fn(() => {});
13 | it("should call callback after resize", () => {
14 | expect.hasAssertions();
15 | renderHook(() => useOnWindowScroll(mockCallback));
16 | fireEvent(window, new Event("scroll"));
17 | expect(mockCallback.mock.calls).toHaveLength(1);
18 | fireEvent(window, new Event("scroll"));
19 | fireEvent(window, new Event("scroll"));
20 | expect(mockCallback.mock.calls).toHaveLength(3);
21 | });
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useOnline.spec.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment jsdom
3 | */
4 | import { renderHook } from "@testing-library/react-hooks";
5 | import { useOnline } from "@/hooks/useOnline";
6 |
7 | describe("useOnline", () => {
8 | let onlineGetter = jest.spyOn(window.navigator, "onLine", "get");
9 |
10 | beforeEach(() => {
11 | onlineGetter = jest.spyOn(window.navigator, "onLine", "get");
12 | });
13 |
14 | it("should be defined", () => {
15 | expect.hasAssertions();
16 | expect(useOnline).toBeDefined();
17 | });
18 |
19 | it("should get the online status", () => {
20 | expect.hasAssertions();
21 | onlineGetter.mockReturnValue(true);
22 | const { result } = renderHook(() => useOnline());
23 | expect(result.current).toBe(true);
24 | });
25 |
26 | it("should get the offline status", () => {
27 | expect.hasAssertions();
28 | onlineGetter.mockReturnValue(false);
29 | const { result } = renderHook(() => useOnline());
30 | expect(result.current).toBe(false);
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/usePreviousImmediate.spec.ts:
--------------------------------------------------------------------------------
1 | import { act, renderHook } from "@testing-library/react-hooks";
2 | import { useState } from "react";
3 | import { usePreviousImmediate } from "@/hooks/usePreviousImmediate";
4 |
5 | describe("usePreviousImmediate", () => {
6 | let useHook = (): {
7 | increment: () => void;
8 | previousValue: number | null;
9 | value: number;
10 | } => {
11 | return {
12 | increment: () => {},
13 | previousValue: 5,
14 | value: 6,
15 | };
16 | };
17 |
18 | beforeEach(() => {
19 | useHook = function () {
20 | const [value, setValue] = useState(0);
21 | const previousValue = usePreviousImmediate(value);
22 | const increment = () => {
23 | setValue(value + 1);
24 | };
25 |
26 | return { increment, previousValue, value };
27 | };
28 | });
29 | it("isDefined", async () => {
30 | expect.hasAssertions();
31 | expect(usePreviousImmediate).toBeDefined();
32 | });
33 | it("initially returns null", async () => {
34 | expect.hasAssertions();
35 | const { result } = renderHook(() => useHook());
36 | expect(result.current.previousValue).toBeNull();
37 | });
38 |
39 | it("holds the previous value", async () => {
40 | expect.hasAssertions();
41 | const { result } = renderHook(() => useHook());
42 | act(() => {
43 | result.current.increment();
44 | });
45 | expect(result.current.value).toBe(1);
46 | expect(result.current.previousValue).toBe(0);
47 | });
48 | });
49 | // figure out tests
50 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useRenderCount.spec.ts:
--------------------------------------------------------------------------------
1 | import { renderHook } from "@testing-library/react";
2 | import { act } from "react-test-renderer";
3 | import { useCounter } from "..";
4 | import { useRenderCount } from "@/hooks/useRenderCount";
5 |
6 | describe("useRenderCount", () => {
7 | it("should be defined", () => {
8 | expect.hasAssertions();
9 | expect(useRenderCount).toBeDefined();
10 | });
11 | it("should return 1 for first render", () => {
12 | expect.hasAssertions();
13 | const { result } = renderHook(() => useRenderCount());
14 | expect(result.current).toBe(1);
15 | });
16 |
17 | it("should increment when component rerenders", () => {
18 | expect.hasAssertions();
19 | const useCustomHook = () => {
20 | const counter = useCounter(0);
21 | const renderCount = useRenderCount();
22 |
23 | return {
24 | renderCount,
25 | counter,
26 | };
27 | };
28 | const { result } = renderHook(useCustomHook);
29 | expect(result.current.counter.value).toBe(0);
30 | expect(result.current.renderCount).toBe(1);
31 | act(() => {
32 | result.current.counter.increment();
33 | });
34 | expect(result.current.counter.value).toBe(1);
35 | expect(result.current.renderCount).toBe(2);
36 | act(() => {
37 | result.current.counter.incrementBy(5);
38 | });
39 | expect(result.current.counter.value).toBe(6);
40 | expect(result.current.renderCount).toBe(3);
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useSelect.spec.ts:
--------------------------------------------------------------------------------
1 | import { renderHook, act } from "@testing-library/react-hooks";
2 | import { useSelect } from "@/hooks/useSelect";
3 |
4 | describe("useSelect", () => {
5 | it("should return correct value at index", () => {
6 | expect.hasAssertions();
7 | let array = [1, 2];
8 | const { result, rerender } = renderHook(() => useSelect(array, 0));
9 |
10 | // test memo
11 | const incrementByBeforeRerender = result.current.setItem;
12 | rerender();
13 | const incrementByAfterRerender = result.current.setItem;
14 | expect(incrementByBeforeRerender).toBe(incrementByAfterRerender);
15 |
16 | // assertions
17 | expect(result.current.index).toBe(0);
18 | expect(result.current.item).toBe(1);
19 |
20 | // should be reactive to the latest memo list
21 | act(() => {
22 | array = [1, 2, 5];
23 | rerender();
24 | });
25 |
26 | act(() => {
27 | result.current.setItem(5);
28 | });
29 |
30 | // assertions
31 | expect(result.current.index).toBe(2);
32 | expect(result.current.item).toBe(5);
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useSetState.spec.ts:
--------------------------------------------------------------------------------
1 | import { renderHook, act } from "@testing-library/react";
2 | import { useSetState } from "../hooks/useSetState";
3 |
4 | describe("useSetState", () => {
5 | it("should be defined", () => {
6 | expect.hasAssertions();
7 | expect(useSetState).toBeDefined();
8 | });
9 |
10 | it("should initialize the state with the initialSetValue", () => {
11 | expect.hasAssertions();
12 | const { result } = renderHook(() => useSetState(new Set([1, 2, 3])));
13 |
14 | expect(result.current[0]).toEqual(new Set([1, 2, 3]));
15 | });
16 |
17 | it("should add values to the set", () => {
18 | expect.hasAssertions();
19 | const { result } = renderHook(() => useSetState(new Set([1, 2, 3])));
20 |
21 | act(() => {
22 | result.current[1].add(4);
23 | });
24 | expect(result.current[0]).toEqual(new Set([1, 2, 3, 4]));
25 | });
26 |
27 | it("should delete values from the set", () => {
28 | expect.hasAssertions();
29 | const { result } = renderHook(() => useSetState(new Set([1, 2, 3])));
30 |
31 | act(() => {
32 | result.current[1].delete(2);
33 | });
34 |
35 | expect(result.current[0]).toEqual(new Set([1, 3]));
36 | });
37 |
38 | it("should clear the set", () => {
39 | expect.hasAssertions();
40 | const { result } = renderHook(() => useSetState(new Set([1, 2, 3])));
41 |
42 | act(() => {
43 | result.current[1].clear();
44 | });
45 | expect(result.current[0]).toEqual(new Set());
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useVideo.spec.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment jsdom
3 | */
4 | import { useVideo } from "@/hooks/useVideo";
5 | // write a simple test which checks if useAudio is defined
6 | describe("useVideo", () => {
7 | it("is defined", () => {
8 | expect.hasAssertions();
9 | expect(useVideo).not.toBeUndefined();
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useWarningOnMountInDevelopment.spec.ts:
--------------------------------------------------------------------------------
1 | import { renderHook } from "@testing-library/react-hooks";
2 | import { useWarningOnMountInDevelopment } from "@/hooks/useWarningOnMountInDevelopment";
3 |
4 | describe("useWarningOnMountInDevelopment", () => {
5 | it("is defined", () => {
6 | expect.hasAssertions();
7 | expect(useWarningOnMountInDevelopment).toBeDefined();
8 | });
9 | it("logs error in dev env", () => {
10 | expect.hasAssertions();
11 | const spy = jest.spyOn(global.console, "error");
12 | renderHook(() => useWarningOnMountInDevelopment("message"));
13 | // eslint-disable-next-line jest/prefer-called-with
14 | expect(spy).toHaveBeenCalled();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useWindowScrollPosition.spec.ts:
--------------------------------------------------------------------------------
1 | import { fireEvent } from "@testing-library/react";
2 | import { act, renderHook } from "@testing-library/react-hooks";
3 | import { useWindowScrollPosition } from "@/hooks/useWindowScrollPosition";
4 |
5 | describe("useWindowScrollPosition", () => {
6 | it("should be defined", () => {
7 | expect.hasAssertions();
8 | expect(useWindowScrollPosition).toBeDefined();
9 | });
10 |
11 | describe("basic", () => {
12 | it("should call callback after resize", () => {
13 | expect.hasAssertions();
14 | const { result } = renderHook(() => useWindowScrollPosition());
15 | expect(result.current.scrollX).toBe(0);
16 | expect(result.current.scrollY).toBe(0);
17 | act(() => {
18 | fireEvent.scroll(window, { target: { pageYOffset: 100 } });
19 | });
20 | expect(result.current.scrollX).toBe(0);
21 | expect(result.current.scrollY).toBe(100);
22 | act(() => {
23 | fireEvent.scroll(window, { target: { pageXOffset: 300 } });
24 | });
25 | expect(result.current.scrollX).toBe(300);
26 | expect(result.current.scrollY).toBe(100);
27 | });
28 | });
29 | });
30 |
31 | // figure out tests
32 |
--------------------------------------------------------------------------------
/packages/rooks/src/__tests__/useWindowSize.spec.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment jsdom
3 | */
4 | import { renderHook } from "@testing-library/react-hooks";
5 | import { useWindowSize } from "@/hooks/useWindowSize";
6 |
7 | describe("useWindowSize", () => {
8 | it("should be defined", () => {
9 | expect.hasAssertions();
10 | expect(useWindowSize).toBeDefined();
11 | });
12 |
13 | describe("basic", () => {
14 | it("should have an initial value on first render", () => {
15 | expect.hasAssertions();
16 | const { result } = renderHook(() => useWindowSize());
17 | expect(result.current.innerHeight).not.toBeNull();
18 | });
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useBoundingclientrect.ts:
--------------------------------------------------------------------------------
1 | import type { MutableRefObject } from "react";
2 | import { useState, useCallback } from "react";
3 | import { useDidMount } from "./useDidMount";
4 | import { useMutationObserver } from "./useMutationObserver";
5 |
6 | /**
7 | * @param element HTML element whose boundingclientrect is needed
8 | * @returns DOMRect
9 | */
10 | function getBoundingClientRect(element: HTMLElement): DOMRect | null {
11 | return element.getBoundingClientRect();
12 | }
13 |
14 | /**
15 | * useBoundingclientRect hook
16 | *
17 | * @param ref The React ref whose ClientRect is needed
18 | * @returns DOMRect | null
19 | * @see https://rooks.vercel.app/docs/useBoundingclientRect
20 | */
21 | function useBoundingclientrect(
22 | ref: MutableRefObject
23 | ): DOMRect | null {
24 | const [domRect, setDomRect] = useState(null);
25 |
26 | const update = useCallback(() => {
27 | setDomRect(ref.current ? getBoundingClientRect(ref.current) : null);
28 | }, [ref]);
29 |
30 | useDidMount(() => {
31 | update();
32 | });
33 |
34 | useMutationObserver(ref, update);
35 |
36 | return domRect;
37 | }
38 |
39 | export { useBoundingclientrect };
40 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useCountdown.ts:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useIntervalWhen } from "./useIntervalWhen";
3 |
4 | type CountdownOptions = {
5 | interval?: number;
6 | onDown?: (restTime: number, newTime: Date) => void;
7 | onEnd?: (newTime: Date) => void;
8 | };
9 |
10 | /**
11 | *
12 | * useCountdown
13 | * Easy way to countdown until a given endtime in intervals
14 | *
15 | * @param endTime Time to countdown
16 | * @param options Countdown options
17 | * @see https://rooks.vercel.app/docs/useCountdown
18 | */
19 | function useCountdown(endTime: Date, options: CountdownOptions = {}): number {
20 | const { interval = 1_000, onDown, onEnd } = options;
21 | const [time, setTime] = useState(() => new Date());
22 | const restTime = endTime.getTime() - time.getTime();
23 | const count = restTime > 0 ? Math.ceil(restTime / interval) : 0;
24 |
25 | useIntervalWhen(onTick, count ? interval : undefined, true, true);
26 |
27 | return count;
28 |
29 | function onTick() {
30 | const newTime = new Date();
31 | if (newTime > endTime) {
32 | if (onEnd) {
33 | onEnd(newTime);
34 | }
35 |
36 | setTime(endTime);
37 |
38 | return;
39 | }
40 |
41 | if (onDown) {
42 | onDown(restTime, newTime);
43 | }
44 |
45 | setTime(newTime);
46 | }
47 | }
48 |
49 | export { useCountdown };
50 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useDeepCompareEffect.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * useDeepCompareEffect
3 | * @description Deep compare dependencies instead of shallow for useEffect
4 | * @see {@link https://rooks.vercel.app/docs/useDeepCompareEffect}
5 | */
6 | import { useEffect, useRef, DependencyList, EffectCallback } from "react";
7 | import isEqual from "fast-deep-equal";
8 | import { warning } from "./warning";
9 |
10 | function isPrimitive(value: unknown) {
11 | const valueType = typeof value;
12 | return (
13 | valueType === "string" ||
14 | valueType === "number" ||
15 | valueType === "bigint" ||
16 | valueType === "boolean" ||
17 | valueType === "undefined" ||
18 | valueType === "symbol"
19 | );
20 | }
21 |
22 | function useDeepCompareEffect(
23 | callback: EffectCallback,
24 | dependencies: DependencyList
25 | ): void {
26 | const previousDeps = useRef(dependencies);
27 |
28 | if (!Array.isArray(dependencies)) {
29 | throw new Error(
30 | "useDeepCompareEffect should be used with an array of dependencies"
31 | );
32 | }
33 |
34 | const hasPrimitives = dependencies.every(isPrimitive);
35 |
36 | warning(
37 | !hasPrimitives,
38 | "useDeepCompareEffect should not be used with primitive values as dependencies"
39 | );
40 |
41 | if (!isEqual(previousDeps.current, dependencies)) {
42 | previousDeps.current = dependencies;
43 | }
44 |
45 | // eslint-disable-next-line react-hooks/exhaustive-deps
46 | useEffect(callback, previousDeps.current);
47 | }
48 |
49 | export { useDeepCompareEffect };
50 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useDidMount.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import type { CallbackWithNoArguments } from "@/types/types";
3 |
4 | /**
5 | * useDidMount hook
6 | * @description Calls a function on mount
7 | *
8 | * @param {Function} callback Callback function to be called on mount
9 | * @see https://rooks.vercel.app/docs/useDidMount
10 | */
11 | function useDidMount(callback: CallbackWithNoArguments): void {
12 | useEffect(() => {
13 | if (typeof callback === "function") {
14 | callback();
15 | }
16 | // eslint-disable-next-line react-hooks/exhaustive-deps
17 | }, []);
18 | }
19 |
20 | export { useDidMount };
21 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useDocumentEventListener.ts:
--------------------------------------------------------------------------------
1 | import { useGlobalObjectEventListener } from "./useGlobalObjectEventListener";
2 | import type { ListenerOptions } from "@/types/utils";
3 |
4 | /**
5 | * useDocumentEventListener hook
6 | *
7 | * @description A react hook to an event listener to the document
8 | *
9 | * @param {keyof DocumentEventMap} eventName The event to track
10 | * @param {Function} callback The callback to be called on event
11 | * @param {ListenerOptions} listenerOptions The options to be passed to the event listener
12 | * @param {boolean} isLayoutEffect Should it use layout effect. Defaults to false
13 | * @see https://rooks.vercel.app/docs/useDocumentEventListener
14 | */
15 | function useDocumentEventListener(
16 | eventName: keyof DocumentEventMap,
17 | callback: (...args: unknown[]) => void,
18 | listenerOptions: ListenerOptions = {},
19 | isLayoutEffect = false
20 | ): void {
21 | useGlobalObjectEventListener(
22 | global.document,
23 | eventName,
24 | callback,
25 | listenerOptions,
26 | true,
27 | isLayoutEffect
28 | );
29 | }
30 |
31 | export { useDocumentEventListener };
32 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useDocumentVisibilityState.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useState } from "react";
2 | import { useGlobalObjectEventListener } from "./useGlobalObjectEventListener";
3 |
4 | type UseDocumentVisibilityStateReturnType = Document["visibilityState"] | null;
5 |
6 | /**
7 | * useDocumentVisibilityState
8 | * @description Returns the visibility state of the document. Returns null on the server side.
9 | * @returns {UseDocumentVisibilityStateReturnType} The visibility state of the document. `null` on the server.
10 | * @see {@link https://rooks.vercel.app/docs/useDocumentVisibilityState}
11 | */
12 | function useDocumentVisibilityState(): UseDocumentVisibilityStateReturnType {
13 | const [visibilityState, setVisibilityState] =
14 | useState(
15 | document ? document.visibilityState : null
16 | );
17 |
18 | const handleVisibilityChange = useCallback(() => {
19 | setVisibilityState(document ? document.visibilityState : null);
20 | }, []);
21 |
22 | useGlobalObjectEventListener(
23 | global.document,
24 | "visibilitychange",
25 | handleVisibilityChange,
26 | {},
27 | true,
28 | true
29 | );
30 |
31 | return visibilityState;
32 | }
33 |
34 | export { useDocumentVisibilityState };
35 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useEffectOnceWhen.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from "react";
2 |
3 | /**
4 | * useEffectOnceWhen hook
5 | *
6 | * @description It fires a callback once when a condition is true or become true.
7 | * Fires the callback at most one time.
8 | *
9 | * @param callback The callback to fire
10 | * @param when The condition which needs to be true
11 | * @see https://rooks.vercel.app/docs/useEffectOnceWhen
12 | */
13 | function useEffectOnceWhen(callback: () => void, when = true): void {
14 | const hasRunOnceRef = useRef(false);
15 | const callbackRef = useRef(callback);
16 | useEffect(() => {
17 | callbackRef.current = callback;
18 | });
19 | useEffect(() => {
20 | if (when && !hasRunOnceRef.current) {
21 | callbackRef.current();
22 | hasRunOnceRef.current = true;
23 | }
24 | }, [when]);
25 | }
26 |
27 | export { useEffectOnceWhen };
28 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useForkRef.ts:
--------------------------------------------------------------------------------
1 | import type { MutableRefObject, RefCallback } from "react";
2 | import { useMemo } from "react";
3 | import type { PossibleRef } from "../utils/utils";
4 | /**
5 | * Credit to material-ui for this snippet
6 | */
7 |
8 | function setRef(ref: PossibleRef | null, value: T) {
9 | if (typeof ref === "function") {
10 | ref(value);
11 | } else if (ref !== null && ref !== undefined) {
12 | (ref as MutableRefObject).current = value;
13 | }
14 | }
15 |
16 | /**
17 | * useForkRef
18 | * Joins refs together and returns a combination of the two as a new ref
19 | *
20 | * @param refA
21 | * @param refB
22 | * @returns MutableRefObject
23 | * @see https://rooks.vercel.app/docs/useForkRef
24 | */
25 | function useForkRef(
26 | refA: PossibleRef | null,
27 | refB: PossibleRef | null
28 | ): RefCallback | null {
29 | /**
30 | * This will create a new function if the ref props change and are defined.
31 | * This means react will call the old forkRef with `null` and the new forkRef
32 | * with the ref. Cleanup naturally emerges from this behavior
33 | */
34 | return useMemo(() => {
35 | if (refA === null && refB === null) {
36 | return null;
37 | }
38 |
39 | return (refValue: T) => {
40 | setRef(refA, refValue);
41 | setRef(refB, refValue);
42 | };
43 | }, [refA, refB]);
44 | }
45 |
46 | export { useForkRef };
47 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useFreshCallback.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * useFreshCallback
3 | * @description Avoid stale closures and keep your callback fresh
4 | * @see {@link https://rooks.vercel.app/docs/useFreshCallback}
5 | */
6 | import { useCallback } from "react";
7 | import { useFreshRef } from "./useFreshRef";
8 |
9 | type CallbackType = (...args: T[]) => R;
10 |
11 | /**
12 | * useFreshCallback
13 | * @param callback Any callback function
14 | * @returns A fresh callback.
15 | * @see https://rooks.vercel.app/docs/useFreshCallback
16 | */
17 | function useFreshCallback(
18 | callback: CallbackType
19 | ): CallbackType {
20 | const freshRef = useFreshRef(callback);
21 | const tick = useCallback<(...args: T[]) => R>(
22 | (...args) => {
23 | return freshRef.current(...args);
24 | },
25 | [freshRef]
26 | );
27 |
28 | return tick;
29 | }
30 |
31 | export { useFreshCallback };
32 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useFreshRef.ts:
--------------------------------------------------------------------------------
1 | import type { MutableRefObject } from "react";
2 | import { useEffect, useRef } from "react";
3 | import { useIsomorphicEffect } from "./useIsomorphicEffect";
4 |
5 | /**
6 | * useFreshRef
7 | *
8 | * @param value The value which needs to be fresh at all times. Probably
9 | * best used with functions
10 | * @param preferLayoutEffect Should the value be updated using a layout effect
11 | * or a passive effect. Defaults to false.
12 | * @returns A ref containing the fresh value
13 | * @see https://rooks.vercel.app/docs/useFreshRef
14 | */
15 | function useFreshRef(
16 | value: T,
17 | preferLayoutEffect = false
18 | ): MutableRefObject {
19 | const useEffectToUse = preferLayoutEffect ? useIsomorphicEffect : useEffect;
20 | const ref = useRef(value);
21 | useEffectToUse(() => {
22 | ref.current = value;
23 | });
24 |
25 | return ref;
26 | }
27 |
28 | export { useFreshRef };
29 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useFreshTick.ts:
--------------------------------------------------------------------------------
1 | import { useFreshRef } from "./useFreshRef";
2 |
3 | type CallbackType = (...args: T[]) => void;
4 | /**
5 | * useFreshTick
6 | * @param callback The callback to be called on mount
7 | * @returns A fresh callback.
8 | * @see https://rooks.vercel.app/docs/useFreshCallback
9 | */
10 | function useFreshTick(callback: CallbackType): CallbackType {
11 | const freshRef = useFreshRef(callback);
12 | function tick(...args: T[]) {
13 | if (typeof freshRef.current === "function") {
14 | freshRef.current(...args);
15 | }
16 | }
17 |
18 | return tick;
19 | }
20 |
21 | export { useFreshTick };
22 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useGetIsMounted.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useEffect, useRef } from "react";
2 |
3 | type UseGetIsMounted = () => () => boolean;
4 |
5 | /**
6 | * @description useGetIsMounted hook checks if a component is mounted or not at the time.
7 | * Useful for async effects. Returns a callback that returns a boolean representing if the component
8 | * is mounted at the time.
9 | * @returns () => boolean
10 | * @see https://rooks.vercel.app/docs/useGetIsMounted
11 | */
12 | export const useGetIsMounted: UseGetIsMounted = () => {
13 | const isMountedRef = useRef(false);
14 | const get = useCallback(() => isMountedRef.current, []);
15 |
16 | useEffect(() => {
17 | isMountedRef.current = true;
18 |
19 | return () => {
20 | isMountedRef.current = false;
21 | };
22 | }, []);
23 |
24 | return get;
25 | };
26 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useIntervalWhen.ts:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react";
2 | import { noop } from "@/utils/noop";
3 |
4 | /**
5 | * A setInterval hook that calls a callback after a interval duration
6 | * when a condition is true
7 | *
8 | * @param callback The callback to be invoked after interval
9 | * @param intervalDurationMs Amount of time in ms after which to invoke
10 | * @param when The condition which when true, sets the interval
11 | * @param startImmediate If the callback should be invoked immediately
12 | * @see https://rooks.vercel.app/docs/useIntervalWhen
13 | */
14 | function useIntervalWhen(
15 | callback: () => void,
16 | intervalDurationMs = 0,
17 | when = true,
18 | startImmediate = false
19 | ): void {
20 | const savedRefCallback = useRef<() => void | undefined>(undefined);
21 |
22 | useEffect(() => {
23 | savedRefCallback.current = callback;
24 | });
25 |
26 | useEffect(() => {
27 | if (when) {
28 | function internalCallback() {
29 | savedRefCallback.current?.();
30 | }
31 |
32 | if (startImmediate) {
33 | internalCallback();
34 | }
35 |
36 | const interval = window.setInterval(internalCallback, intervalDurationMs);
37 |
38 | return () => {
39 | window.clearInterval(interval);
40 | };
41 | }
42 |
43 | return noop;
44 | }, [when, intervalDurationMs, startImmediate]);
45 | }
46 |
47 | export { useIntervalWhen };
48 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useIsomorphicEffect.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useLayoutEffect } from "react";
2 |
3 | /**
4 | * useIsomorphicEffect
5 | * Resolves to useEffect when "window" is not in scope and useLayout effect in the browser
6 | *
7 | * @param {Function} callback Callback function to be called on mount
8 | * @see https://rooks.vercel.app/docs/useIsomorphicEffect
9 | */
10 | const useIsomorphicEffect =
11 | typeof window === "undefined" ? useEffect : useLayoutEffect;
12 |
13 | export { useIsomorphicEffect };
14 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useKeyBindings.ts:
--------------------------------------------------------------------------------
1 |
2 | import type { RefObject } from "react";
3 | import { useKey } from "./useKey";
4 |
5 | type TrackedKeyEvents = "keydown" | "keypress" | "keyup";
6 |
7 | type Options = {
8 | /**
9 | * Keyboardevent types to listen for. Valid options are keyDown, keyPress and keyUp
10 | */
11 | eventTypes?: TrackedKeyEvents[];
12 | /**
13 | * target ref on which the events should be listened. If no target is specified,
14 | * events are listened to on the window. Only works with object refs. If you want to use with callback refs,
15 | * please use useKeyRef instead.
16 | */
17 | target?: RefObject;
18 | /**
19 | * Condition which if true, will enable the event listeners
20 | */
21 | when?: boolean;
22 | };
23 |
24 | type KeyBindings = { [key: string]: (event: KeyboardEvent) => void };
25 |
26 | /**
27 | * useKeyBindings
28 | *
29 | * useKeyBindings binds pairs of keyboard events and handlers
30 | *
31 | * @param { KeyBindings } keyBindings
32 | * @param {Options} options
33 | * @see https://rooks.vercel.app/docs/useKeyBindings
34 | */
35 | const useKeyBindings = (keyBindings: KeyBindings, options?: Options) => {
36 | for (const key in keyBindings) {
37 |
38 | const handler = keyBindings[key];
39 | if (handler) {
40 | useKey(key, handler, options);
41 | }
42 | }
43 | };
44 |
45 | export { useKeyBindings };
46 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useLifecycleLogger.ts:
--------------------------------------------------------------------------------
1 | import { useDidMount } from "./useDidMount";
2 | import { useDidUpdate } from "./useDidUpdate";
3 | import { useWillUnmount } from "./useWillUnmount";
4 |
5 | /**
6 | * useLifecycleLogger hook
7 | * logs parameters as component transitions through lifecycles
8 | *
9 | * @param componentName Name of the component
10 | * @param {...*} otherArgs Other arguments to log
11 | * @see https://rooks.vercel.app/docs/useLifecycleLogger
12 | */
13 | const useLifecycleLogger = (
14 | componentName = "Component",
15 | ...otherArgs: unknown[]
16 | ) => {
17 | useDidMount(() => {
18 | console.log(`${componentName} mounted`, ...otherArgs);
19 |
20 | return () => console.log(`${componentName} unmounted`);
21 | });
22 |
23 | useDidUpdate(() => {
24 | console.log(`${componentName} updated`, ...otherArgs);
25 | });
26 |
27 | useWillUnmount(() => {
28 | console.log(`${componentName} unmounted`);
29 | });
30 | };
31 |
32 | export { useLifecycleLogger };
33 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useLockBodyScroll.ts:
--------------------------------------------------------------------------------
1 | import { noop } from "@/utils/noop";
2 | import { useEffect } from "react";
3 |
4 | /**
5 | * useLockBodyScroll hook
6 | *
7 | * This hook locks the scroll of the body element when `isLocked` is set to `true`.
8 | *
9 | * @param isLocked Whether or not to lock the body scroll
10 | * @see https://rooks.vercel.app/docs/useLockBodyScroll
11 | */
12 | function useLockBodyScroll(isLocked: boolean) {
13 | useEffect(() => {
14 | if (isLocked) {
15 | // Get the original body overflow value
16 | const originalOverflow = window.getComputedStyle(document.body).overflow;
17 |
18 | // Set overflow to hidden to lock the scroll
19 | document.body.style.overflow = "hidden";
20 |
21 | // Return a cleanup function that resets the overflow back to the original value
22 | return () => {
23 | document.body.style.overflow = originalOverflow;
24 | };
25 | } else {
26 | return noop;
27 | }
28 | }, [isLocked]);
29 | }
30 |
31 | export { useLockBodyScroll };
32 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useMediaMatch.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useMemo, useState } from "react";
2 |
3 | /**
4 | * useMediaMatch
5 | *
6 | * A react hook that signals whether or not a media query is matched.
7 | *
8 | * @param query The media query to signal on. Example, `"print"` will signal
9 | * `true` when previewing in print mode, and `false` otherwise.
10 | * @returns Whether or not the media query is currently matched.
11 | * @see https://rooks.vercel.app/docs/useMediaMatch
12 | */
13 | function useMediaMatch(query: string): boolean {
14 | const matchMedia = useMemo(
15 | () => window.matchMedia(query),
16 | [query]
17 | );
18 | const [matches, setMatches] = useState(() => matchMedia.matches);
19 |
20 | useEffect(() => {
21 | setMatches(matchMedia.matches);
22 | const listener = (event: MediaQueryListEventMap["change"]) =>
23 | setMatches(event.matches);
24 |
25 | if (matchMedia.addEventListener) {
26 | matchMedia.addEventListener("change", listener);
27 | return () => matchMedia.removeEventListener("change", listener);
28 | } else {
29 | matchMedia.addListener(listener);
30 | return () => matchMedia.removeListener(listener);
31 | }
32 | }, [matchMedia]);
33 |
34 | if (typeof window === "undefined") {
35 | console.warn("useMediaMatch cannot function as window is undefined.");
36 |
37 | return false;
38 | }
39 |
40 | return matches;
41 | }
42 |
43 | export { useMediaMatch };
44 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useMergeRefs.ts:
--------------------------------------------------------------------------------
1 | import type { MutableRefObject, RefCallback } from "react";
2 | import { useMemo } from "react";
3 | import type { PossibleRef } from "../utils/utils";
4 |
5 | function setRef(ref: PossibleRef, value: T) {
6 | if (typeof ref === "function") {
7 | ref(value);
8 | } else if (ref !== null && ref !== undefined) {
9 | (ref as MutableRefObject).current = value;
10 | }
11 | }
12 |
13 | /**
14 | * useMergeRefs
15 | * Merges multiple refs into a single function ref.
16 | * Takes any number of refs.
17 | * Refs can be mutable refs or function refs.
18 | *
19 | * @param refs
20 | * @see https://rooks.vercel.app/docs/useMergeRefs
21 | */
22 | export function useMergeRefs(
23 | ...refs: Array>
24 | ): RefCallback | null {
25 | return useMemo(() => {
26 | if (refs.every((ref) => ref === null)) {
27 | return null;
28 | }
29 |
30 | return (refValue: T) => {
31 | for (const ref of refs) {
32 | setRef(ref, refValue);
33 | }
34 | };
35 | }, [refs]);
36 | }
37 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useMutationObserver.ts:
--------------------------------------------------------------------------------
1 | import type { MutableRefObject } from "react";
2 | import { useEffect } from "react";
3 | import { noop } from "@/utils/noop";
4 |
5 | const config: MutationObserverInit = {
6 | attributes: true,
7 | characterData: true,
8 | childList: true,
9 | subtree: true,
10 | };
11 |
12 | /**
13 | *
14 | * useMutationObserver hook
15 | *
16 | * Returns a mutation observer for a React Ref and fires a callback
17 | *
18 | * @param {MutableRefObject} ref React ref on which mutations are to be observed
19 | * @param {MutationCallback} callback Function that needs to be fired on mutation
20 | * @param {MutationObserverInit} options
21 | * @see https://rooks.vercel.app/docs/useMutationObserver
22 | */
23 | function useMutationObserver(
24 | ref: MutableRefObject,
25 | callback: MutationCallback,
26 | options: MutationObserverInit = config
27 | ): void {
28 | useEffect(() => {
29 | // Create an observer instance linked to the callback function
30 | if (ref.current) {
31 | const observer = new MutationObserver(callback);
32 |
33 | // Start observing the target node for configured mutations
34 | observer.observe(ref.current, options);
35 |
36 | return () => {
37 | observer.disconnect();
38 | };
39 | }
40 |
41 | return noop;
42 | }, [callback, options, ref]);
43 | }
44 |
45 | export { useMutationObserver };
46 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useMutationObserverRef.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useCallback, useState } from "react";
2 | import type { CallbackRef, HTMLElementOrNull } from "../utils/utils";
3 | import { noop } from "@/utils/noop";
4 |
5 | const config: MutationObserverInit = {
6 | attributes: true,
7 | characterData: true,
8 | childList: true,
9 | subtree: true,
10 | };
11 |
12 | /**
13 | *
14 | * useMutationObserverRef hook
15 | *
16 | * Returns a mutation observer for a React Ref and fires a callback
17 | *
18 | * @param {MutationCallback} callback Function that needs to be fired on mutation
19 | * @param {MutationObserverInit} options
20 | * @see https://rooks.vercel.app/docs/useMutationObserverRef
21 | */
22 | function useMutationObserverRef(
23 | callback: MutationCallback,
24 | options: MutationObserverInit = config
25 | ): [CallbackRef] {
26 | const [node, setNode] = useState(null);
27 |
28 | useEffect(() => {
29 | // Create an observer instance linked to the callback function
30 | if (node) {
31 | const observer = new MutationObserver(callback);
32 |
33 | // Start observing the target node for configured mutations
34 | observer.observe(node, options);
35 |
36 | return () => {
37 | observer.disconnect();
38 | };
39 | }
40 |
41 | return noop;
42 | }, [node, callback, options]);
43 |
44 | const ref: CallbackRef = useCallback((nodeElement: HTMLElementOrNull) => {
45 | setNode(nodeElement);
46 | }, []);
47 |
48 | return [ref];
49 | }
50 |
51 | export { useMutationObserverRef };
52 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useNavigatorLanguage.ts:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useWindowEventListener } from "./useWindowEventListener";
3 |
4 | type Language = string | null;
5 |
6 | function getLanguage(): Language {
7 | // eslint-disable-next-line no-negated-condition
8 | if (typeof navigator !== "undefined") {
9 | // eslint-disable-next-line @typescript-eslint/dot-notation
10 | return navigator.language;
11 | } else {
12 | return null;
13 | }
14 | }
15 |
16 | /**
17 | * useNavigatorLanguage hook
18 | * Returns the language of the navigator
19 | *
20 | * @returns {Language}
21 | * @see https://rooks.vercel.app/docs/useNavigatorLanguage
22 | */
23 | export function useNavigatorLanguage(): Language {
24 | const [language, setLanguage] = useState(getLanguage);
25 |
26 | useWindowEventListener("languagechange", () => {
27 | setLanguage(getLanguage);
28 | });
29 |
30 | return language;
31 | }
32 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useOnClickRef.ts:
--------------------------------------------------------------------------------
1 | import { noop } from "@/utils/noop";
2 | import { useState, useEffect, useCallback } from "react";
3 | import { useFreshCallback } from "./useFreshCallback";
4 |
5 | /**
6 | * useOnClickRef hook
7 | *
8 | * This hook runs a callback for both clicks and tap events when the element is clicked or tapped.
9 | *
10 | * @param {Function} onClick The callback function to run on click or tap
11 | * @returns {Function} A callback ref which can be attached to an element
12 | */
13 | function useOnClickRef(onClick: () => void) {
14 | const [node, setNode] = useState(null);
15 | const handleEvent = useCallback(
16 | (event: MouseEvent | TouchEvent) => {
17 | event.preventDefault();
18 | onClick();
19 | },
20 | [onClick]
21 | );
22 |
23 | const freshCallback = useFreshCallback(handleEvent);
24 |
25 | useEffect(() => {
26 | if (node) {
27 | node.addEventListener("click", freshCallback);
28 | node.addEventListener("touchend", freshCallback);
29 |
30 | return () => {
31 | node.removeEventListener("click", freshCallback);
32 | node.removeEventListener("touchend", freshCallback);
33 | };
34 | }
35 | return noop;
36 | }, [node, freshCallback]);
37 |
38 | const ref = useCallback((element: HTMLElement) => {
39 | if (element) {
40 | setNode(element);
41 | }
42 | }, []);
43 |
44 | return ref;
45 | }
46 |
47 | export { useOnClickRef };
48 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useOnHoverRef.ts:
--------------------------------------------------------------------------------
1 | import { noop } from "@/utils/noop";
2 | import { useState, useEffect, RefCallback, useCallback } from "react";
3 | import { useFreshCallback } from "./useFreshCallback";
4 |
5 | type MouseEventHandler = (event: MouseEvent) => void;
6 |
7 | function useOnHoverRef(
8 | onMouseEnter?: MouseEventHandler,
9 | onMouseLeave?: MouseEventHandler
10 | ): RefCallback {
11 | const [node, setNode] = useState(null);
12 |
13 | const handleMouseEnter = useCallback(
14 | (e: MouseEvent) => {
15 | onMouseEnter?.(e);
16 | },
17 | [onMouseEnter]
18 | );
19 |
20 | const handleMouseLeave = useCallback(
21 | (e: MouseEvent) => {
22 | onMouseLeave?.(e);
23 | },
24 | [onMouseLeave]
25 | );
26 |
27 | const mouseEnterCallback = useFreshCallback(handleMouseEnter);
28 | const mouseLeaveCallback = useFreshCallback(handleMouseLeave);
29 | useEffect(() => {
30 | if (node) {
31 | node.addEventListener("mouseenter", mouseEnterCallback);
32 | node.addEventListener("mouseleave", mouseLeaveCallback);
33 |
34 | return () => {
35 | node.removeEventListener("mouseenter", mouseEnterCallback);
36 | node.removeEventListener("mouseleave", mouseLeaveCallback);
37 | };
38 | } else {
39 | return noop;
40 | }
41 | }, [mouseEnterCallback, mouseLeaveCallback, node]);
42 |
43 | const ref: RefCallback = (el) => {
44 | setNode(el);
45 | };
46 |
47 | return ref;
48 | }
49 |
50 | export { useOnHoverRef };
51 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useOnWindowResize.ts:
--------------------------------------------------------------------------------
1 | import { useGlobalObjectEventListener } from "./useGlobalObjectEventListener";
2 |
3 | /**
4 | *
5 | * useOnWindowResize hook
6 | *
7 | * Fires a callback when window resizes
8 | *
9 | * @param {Function} callback Callback to be called before unmount
10 | * @param {boolean} when When the handler should be applied
11 | * @param {boolean} isLayoutEffect Should it use layout effect. Defaults to false
12 | * @see https://rooks.vercel.app/docs/useOnWindowResize
13 | */
14 | function useOnWindowResize(
15 | callback: EventListener,
16 | when = true,
17 | isLayoutEffect = false
18 | ) {
19 | useGlobalObjectEventListener(
20 | global.window,
21 | "resize",
22 | callback,
23 | { passive: true },
24 | when,
25 | isLayoutEffect
26 | );
27 | }
28 |
29 | export { useOnWindowResize };
30 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useOnWindowScroll.ts:
--------------------------------------------------------------------------------
1 | import { useGlobalObjectEventListener } from "./useGlobalObjectEventListener";
2 |
3 | /**
4 | *
5 | * useOnWindowScroll hook
6 | * Fires a callback when window scroll
7 | *
8 | * @param {Function} callback Callback to be called before unmount
9 | * @param {boolean} when When the handler should be applied
10 | * @param {boolean} isLayoutEffect Should it use layout effect. Defaults to false
11 | * @see https://rooks.vercel.app/docs/useOnWindowScroll
12 | *
13 | */
14 | function useOnWindowScroll(
15 | callback: EventListener,
16 | when = true,
17 | isLayoutEffect = false
18 | ): void {
19 | useGlobalObjectEventListener(
20 | global.window,
21 | "scroll",
22 | callback,
23 | { passive: true },
24 | when,
25 | isLayoutEffect
26 | );
27 | }
28 |
29 | export { useOnWindowScroll };
30 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useOnline.ts:
--------------------------------------------------------------------------------
1 | import { useSyncExternalStore } from "use-sync-external-store/shim";
2 | import { noop } from "@/utils/noop";
3 |
4 | /**
5 | *
6 | * @returns {boolean} Is navigator online
7 | */
8 | function getSnapshot(): boolean | null {
9 | if (typeof window === "undefined") {
10 | return null;
11 | }
12 |
13 | return navigator.onLine;
14 | }
15 |
16 | function subscribe(onStoreChange: () => void): () => void {
17 | if (typeof window !== "undefined") {
18 | window.addEventListener("online", onStoreChange);
19 | window.addEventListener("offline", onStoreChange);
20 | return () => {
21 | window.removeEventListener("online", onStoreChange);
22 | window.removeEventListener("offline", onStoreChange);
23 | };
24 | } else {
25 | console.warn("useOnline: window is undefined.");
26 | return noop;
27 | }
28 | }
29 |
30 | /**
31 | * useOnline hook
32 | *
33 | * Returns true if navigator is online, false if not.
34 | *
35 | * @returns {boolean} The value of navigator.onLine
36 | * @see https://rooks.vercel.app/docs/useOnline
37 | */
38 | function useOnline(): boolean | null {
39 | const isOnline = useSyncExternalStore(subscribe, getSnapshot);
40 |
41 | return isOnline;
42 | }
43 |
44 | export { useOnline };
45 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useOrientation.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * useOrientation
3 | * @description orientation hook for react
4 | * @see {@link https://rooks.vercel.app/docs/useOrientation}
5 | */
6 | import { useState, useEffect } from "react";
7 |
8 | const useOrientation = (): ScreenOrientation | null => {
9 | const [orientation, setOrientation] = useState(
10 | typeof window !== "undefined" ? window.screen.orientation : null
11 | );
12 |
13 | useEffect(() => {
14 | const handleOrientationChange = () => {
15 | setOrientation(window.screen.orientation);
16 | };
17 |
18 | window.screen.orientation.addEventListener(
19 | "change",
20 | handleOrientationChange
21 | );
22 |
23 | return () => {
24 | window.screen.orientation.removeEventListener(
25 | "change",
26 | handleOrientationChange
27 | );
28 | };
29 | }, []);
30 |
31 | return orientation;
32 | };
33 |
34 | export { useOrientation };
35 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/usePreviousDifferent.ts:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react";
2 |
3 | /**
4 | * usePreviousDifferent hook for React
5 | * It returns the past value which was different from the current one.
6 | *
7 | * @param currentValue The value whose previously different value is to be tracked
8 | * @returns The previous value
9 | * @see https://rooks.vercel.app/docs/usePreviousDifferent
10 | */
11 | function usePreviousDifferent(currentValue: T): T | null {
12 | const previousRef = useRef(null);
13 | const previousRef2 = useRef(null);
14 |
15 | useEffect(() => {
16 | previousRef2.current = previousRef.current;
17 | previousRef.current = currentValue;
18 | }, [currentValue]);
19 |
20 | return currentValue === previousRef.current
21 | ? previousRef2.current
22 | : previousRef.current;
23 | }
24 |
25 | export { usePreviousDifferent };
26 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/usePreviousImmediate.ts:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react";
2 |
3 | /**
4 | * usePreviousImmediate hook for React
5 | *
6 | * @param currentValue The value whose previous value is to be tracked
7 | * @returns The previous value
8 | * @see https://rooks.vercel.app/docs/usePreviousImmediate
9 | */
10 | function usePreviousImmediate(currentValue: T): T | null {
11 | const previousRef = useRef(null);
12 |
13 | useEffect(() => {
14 | previousRef.current = currentValue;
15 | });
16 |
17 | return previousRef.current;
18 | }
19 |
20 | export { usePreviousImmediate };
21 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useQueueState.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useState } from "react";
2 | /**
3 | * useQueueState
4 | * Manages a queue with react hooks.
5 | * @param initialList Initial value of the list
6 | * @returns The list and controls to modify the queue
7 | * @see https://rooks.vercel.app/docs/useQueueState
8 | */
9 | function useQueueState(initialList: T[]): [
10 | T[],
11 | {
12 | dequeue: () => T | undefined;
13 | enqueue: (item: T) => number;
14 | length: number;
15 | peek: () => T | undefined;
16 | }
17 | ] {
18 | const [list, setList] = useState([...initialList]);
19 |
20 | const enqueue = useCallback(
21 | (item: T) => {
22 | const newList = [...list, item];
23 |
24 | setList(newList);
25 |
26 | return newList.length;
27 | },
28 | [list]
29 | );
30 |
31 | const dequeue = useCallback(() => {
32 | if (list.length > 0) {
33 | const firstItem = list[0];
34 | setList([...list.slice(1)]);
35 |
36 | return firstItem;
37 | }
38 |
39 | return undefined;
40 | }, [list]);
41 |
42 | const peek = useCallback(() => {
43 | if (list.length > 0) {
44 | return list[0];
45 | }
46 |
47 | return undefined;
48 | }, [list]);
49 |
50 | const controls = {
51 | dequeue,
52 | enqueue,
53 | length: list.length,
54 | peek,
55 | };
56 |
57 | return [list, controls];
58 | }
59 |
60 | export { useQueueState };
61 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useRaf.ts:
--------------------------------------------------------------------------------
1 | import raf from "raf";
2 | import { useRef, useEffect } from "react";
3 | import { noop } from "@/utils/noop";
4 |
5 | /**
6 | *
7 | * useRaf
8 | * Uses a polyfilled version of requestAnimationFrame
9 | *
10 | * @param {Function} callback The callback function to be executed
11 | * @param {boolean} [isActive] The value which while true, keeps the raf running infinitely
12 | * @see https://rooks.vercel.app/docs/useRaf
13 | */
14 | export function useRaf(
15 | callback: (timeElapsed: number) => void,
16 | isActive: boolean
17 | ): void {
18 | const savedCallback = useRef<(timeElapsed: number) => void>(null);
19 | // Remember the latest function.
20 | useEffect(() => {
21 | savedCallback.current = callback;
22 | }, [callback]);
23 |
24 | useEffect(() => {
25 | let animationFrame: number | undefined;
26 | let startTime: number = Date.now();
27 |
28 | function tick() {
29 | const timeElapsed = Date.now() - startTime;
30 | startTime = Date.now();
31 | loop();
32 | savedCallback.current?.(timeElapsed);
33 | }
34 |
35 | function loop() {
36 | animationFrame = raf(tick);
37 | }
38 |
39 | if (isActive) {
40 | startTime = Date.now();
41 | loop();
42 |
43 | return () => {
44 | if (animationFrame) {
45 | raf.cancel(animationFrame);
46 | }
47 | };
48 | } else {
49 | return noop;
50 | }
51 | }, [isActive]);
52 | }
53 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useRefElement.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useState } from "react";
2 | import type { RefElementOrNull } from "../utils/utils";
3 |
4 | /**
5 | * useRefElement hook for React
6 | * Helps bridge gap between callback ref and state
7 | * Manages the element called with callback ref api using state variable
8 | * @returns {[RefElementOrNull, (element: HTMLElementOrNull) => void]}
9 | * @see https://rooks.vercel.app/docs/useRefElement
10 | */
11 | function useRefElement(): [
12 | (refElement: RefElementOrNull) => void,
13 | RefElementOrNull
14 | ] {
15 | const [refElement, setRefElement] = useState>(null);
16 | const ref = useCallback<(refElement: RefElementOrNull) => void>(
17 | (element: RefElementOrNull) => {
18 | setRefElement(element);
19 | },
20 | []
21 | );
22 |
23 | return [ref, refElement];
24 | }
25 |
26 | export { useRefElement };
27 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useRenderCount.ts:
--------------------------------------------------------------------------------
1 | import { useRef } from "react";
2 |
3 | /**
4 | * useRenderCount
5 | * @description Get the render count of a component
6 | * @see {@link https://rooks.vercel.app/docs/useRenderCount}
7 | */
8 | function useRenderCount(): number {
9 | return ++useRef(0).current;
10 | }
11 |
12 | export { useRenderCount };
13 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useSafeSetState.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * useSafeSetState
3 | * @description set state but ignores if component has already unmounted
4 | * @see {@link https://rooks.vercel.app/docs/useSafeSetState}
5 | */
6 | import { useState, useCallback, SetStateAction, Dispatch } from "react";
7 | import { useGetIsMounted } from "./useGetIsMounted";
8 |
9 | function useSafeSetState(initialState: T): [T, Dispatch>] {
10 | const [state, setState] = useState(initialState);
11 | const getIsMounted = useGetIsMounted();
12 |
13 | const safeSetState = useCallback(
14 | (newState: SetStateAction) => {
15 | if (getIsMounted()) {
16 | setState(newState);
17 | }
18 | },
19 | [getIsMounted]
20 | );
21 |
22 | return [state, safeSetState];
23 | }
24 |
25 | export { useSafeSetState };
26 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useSelect.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useState } from "react";
2 |
3 | type SelectHandler = {
4 | index: number;
5 | item: T;
6 | setIndex: (newIndex: number) => void;
7 | setItem: (newItem: T) => void;
8 | };
9 |
10 | /**
11 | * useSelect hook
12 | * Helps easily select a value from a list of values
13 | *
14 | * @param list List of values to select a value from
15 | * @param {number} initialIndex Initial index which is selected
16 | * @returns handler
17 | * @see https://rooks.vercel.app/docs/useSelect
18 | */
19 | function useSelect(list: T[], initialIndex = 0): SelectHandler {
20 | const [selectedIndex, setSelectedIndex] = useState(initialIndex);
21 |
22 | const setItem = useCallback(
23 | (item: T) => {
24 | setSelectedIndex(list.indexOf(item));
25 | },
26 | [list]
27 | );
28 |
29 | return {
30 | index: selectedIndex,
31 | item: list[selectedIndex] as T,
32 | setIndex: setSelectedIndex,
33 | setItem,
34 | };
35 | }
36 |
37 | export { useSelect };
38 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useThrottle.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback, useRef } from "react";
2 | import { noop } from "@/utils/noop";
3 |
4 | type Callback = (...args: T[]) => void;
5 |
6 | /**
7 | * useThrottle
8 | * Throttles a function with a timeout and ensures
9 | * that the callback function runs at most once in that duration
10 | *
11 | * @param callback The callback to throttle
12 | * @param timeout Throttle timeout
13 | * @returns [Callback, isReady] The throttled callback and if it is currently throttled
14 | * @see https://rooks.vercel.app/docs/useThrottle
15 | */
16 | function useThrottle(
17 | callback: Callback,
18 | timeout = 300
19 | ): [Callback, boolean] {
20 | const [ready, setReady] = useState(true);
21 | const timerRef = useRef(undefined);
22 |
23 | const throttledFunction = useCallback(
24 | (...args: T[]) => {
25 | if (!ready) {
26 | return;
27 | }
28 |
29 | setReady(false);
30 | callback(...args);
31 | },
32 | [ready, callback]
33 | );
34 |
35 | useEffect(() => {
36 | if (!ready) {
37 | timerRef.current = window.setTimeout(() => {
38 | setReady(true);
39 | }, timeout);
40 |
41 | return () => window.clearTimeout(timerRef.current);
42 | }
43 |
44 | return noop;
45 | }, [ready, timeout]);
46 |
47 | return [throttledFunction, ready];
48 | }
49 |
50 | export { useThrottle };
51 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useTimeoutWhen.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { noop } from "@/utils/noop";
3 | import { useFreshCallback } from "./useFreshCallback";
4 |
5 | /**
6 | * A setTimeout hook that calls a callback after a timeout duration
7 | * when a condition is true
8 | *
9 | * @param callback The callback to be invoked after timeout
10 | * @param timeoutDelayMs Amount of time in ms after which to invoke
11 | * @param when The condition which when true, sets the timeout
12 | * @see https://rooks.vercel.app/docs/useTimeoutWhen
13 | */
14 | function useTimeoutWhen(
15 | callback: () => void,
16 | timeoutDelayMs = 0,
17 | when = true,
18 | key: string | number = 0
19 | ): void {
20 | const freshCallback = useFreshCallback(callback);
21 |
22 | useEffect(() => {
23 | if (when) {
24 | function internalCallback() {
25 | freshCallback();
26 | }
27 | // eslint-disable-next-line no-negated-condition
28 | if (typeof window !== "undefined") {
29 | const timeout = window.setTimeout(internalCallback, timeoutDelayMs);
30 |
31 | return () => {
32 | window.clearTimeout(timeout);
33 | };
34 | } else {
35 | console.warn("useTimeoutWhen: window is undefined.");
36 | }
37 | }
38 |
39 | return noop;
40 | }, [timeoutDelayMs, when, key, freshCallback]);
41 | }
42 |
43 | export { useTimeoutWhen };
44 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useVibrate.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * useVibrate
3 | * @description Vibration API hook for React
4 | * @see {@link https://rooks.vercel.app/docs/useVibrate}
5 | */
6 | import { useEffect } from "react";
7 |
8 | type UseVibrateOptions = {
9 | isEnabled: boolean;
10 | pattern: number | number[];
11 | };
12 |
13 | function useVibrate({ isEnabled, pattern }: UseVibrateOptions): void {
14 | useEffect(() => {
15 | if (!("vibrate" in navigator) || typeof navigator.vibrate !== "function") {
16 | console.warn("Vibration API not supported by the current browser");
17 | return;
18 | }
19 |
20 | if (isEnabled) {
21 | navigator.vibrate(pattern);
22 | } else {
23 | navigator.vibrate(0);
24 | }
25 |
26 | return () => {
27 | navigator.vibrate(0);
28 | };
29 | }, [isEnabled, pattern]);
30 | }
31 |
32 | export { useVibrate };
33 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useWarningOnMountInDevelopment.ts:
--------------------------------------------------------------------------------
1 | import { useDidMount } from "./useDidMount";
2 | import { warning } from "./warning";
3 |
4 | /**
5 | * useWarningOnMountInDevelopment
6 | * @param message The message to be shown in the console
7 | * @see https://rooks.vercel.app/docs/useWarningOnMountInDevelopment
8 | */
9 | function useWarningOnMountInDevelopment(message: string) {
10 | useDidMount(() => {
11 | warning(false, message);
12 | });
13 | }
14 |
15 | export { useWarningOnMountInDevelopment };
16 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useWhyDidYouUpdate.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * useWhyDidYouUpdate
3 | * @description A hook that can track which value change caused a rerender
4 | * @see {@link https://rooks.vercel.app/docs/useWhyDidYouUpdate}
5 | */
6 | import { useEffect, useRef } from "react";
7 | import { useDidUpdate } from "./useDidUpdate";
8 |
9 | export type PropsRecord = Record;
10 |
11 | export function useWhyDidYouUpdate(
12 | componentName: string,
13 | currentProps: PropsRecord,
14 | enableLogging = true
15 | ) {
16 | const previousProps = useRef({});
17 | useDidUpdate(() => {
18 | if (previousProps.current && enableLogging) {
19 | const combinedKeys = Object.keys({
20 | ...previousProps.current,
21 | ...currentProps,
22 | });
23 | const changedProps: PropsRecord = {};
24 | combinedKeys.forEach((key) => {
25 | if (!Object.is(previousProps.current[key], currentProps[key])) {
26 | changedProps[key] = {
27 | from: previousProps.current[key],
28 | to: currentProps[key],
29 | };
30 | }
31 | });
32 |
33 | if (Object.keys(changedProps).length) {
34 | console.log("[why-did-you-update]", componentName, changedProps);
35 | }
36 | }
37 | }, [currentProps, componentName, enableLogging]);
38 |
39 | useEffect(() => {
40 | previousProps.current = currentProps;
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useWillUnmount.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 |
3 | type Callback = () => void;
4 |
5 | /**
6 | * useWillUnmount hook
7 | * Fires a callback just before component unmounts
8 | *
9 | * @param {Function} callback Callback to be called before unmount
10 | * @see https://rooks.vercel.app/docs/useWillUnmount
11 | */
12 | function useWillUnmount(callback: Callback): void {
13 | // run only once
14 | useEffect(() => {
15 | return callback;
16 | // eslint-disable-next-line react-hooks/exhaustive-deps
17 | }, []);
18 | }
19 |
20 | export { useWillUnmount };
21 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useWindowEventListener.ts:
--------------------------------------------------------------------------------
1 | import { useGlobalObjectEventListener } from "./useGlobalObjectEventListener";
2 | import type { ListenerOptions } from "@/types/utils";
3 |
4 | /**
5 | * useWindowEventListener hook
6 | *
7 | * A react hook to an event listener to the window
8 | *
9 | * @param {keyof WindowEventMap} eventName The event to track
10 | * @param {Function} callback The callback to be called on event
11 | * @param {ListenerOptions} listenerOptions The options to be passed to the event listener
12 | * @param {boolean} isLayoutEffect Should it use layout effect. Defaults to false
13 | * @returns {undefined}
14 | * @see https://rooks.vercel.app/docs/useWindowEventListener
15 | */
16 | function useWindowEventListener(
17 | eventName: keyof WindowEventMap,
18 | callback: (...args: unknown[]) => void,
19 | listenerOptions: ListenerOptions = {},
20 | isLayoutEffect = false
21 | ): void {
22 | useGlobalObjectEventListener(
23 | global.window,
24 | eventName,
25 | callback,
26 | listenerOptions,
27 | true,
28 | isLayoutEffect
29 | );
30 | }
31 |
32 | export { useWindowEventListener };
33 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/useWindowScrollPosition.ts:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useOnWindowResize } from "./useOnWindowResize";
3 | import { useOnWindowScroll } from "./useOnWindowScroll";
4 |
5 | type ScrollPosition = {
6 | scrollX: Window["scrollX"];
7 | scrollY: Window["scrollY"];
8 | };
9 |
10 | function computeScrollPosition(): ScrollPosition {
11 | if (typeof window === "undefined") {
12 | return {
13 | scrollX: 0,
14 | scrollY: 0,
15 | };
16 | } else {
17 | return {
18 | scrollX: window.scrollX || window.pageXOffset,
19 | scrollY: window.scrollY || window.pageYOffset,
20 | };
21 | }
22 | }
23 |
24 | /**
25 | *
26 | * useWindowScrollPosition hook
27 | * A React hook to get the scroll position of the window
28 | *
29 | * @returns an object containing scrollX and scrollY values
30 | * @see https://rooks.vercel.app/docs/useWindowScrollPosition
31 | */
32 | function useWindowScrollPosition(): ScrollPosition {
33 | const [scrollPosition, setScrollPosition] = useState(
34 | computeScrollPosition
35 | );
36 | /**
37 | * Recalculate on scroll
38 | */
39 | useOnWindowScroll(
40 | () => {
41 | setScrollPosition(computeScrollPosition());
42 | },
43 | true,
44 | true
45 | );
46 | /**
47 | * Recalculate on resize
48 | */
49 | useOnWindowResize(
50 | () => {
51 | setScrollPosition(computeScrollPosition());
52 | },
53 | true,
54 | true
55 | );
56 |
57 | return scrollPosition;
58 | }
59 |
60 | export { useWindowScrollPosition };
61 |
--------------------------------------------------------------------------------
/packages/rooks/src/hooks/warning.ts:
--------------------------------------------------------------------------------
1 | const isDevelopmentEnvironment = process.env.NODE_ENV !== "production";
2 |
3 | type Warning = (condition: boolean, message: string) => void;
4 | type PrintWarning = (message: string) => void;
5 |
6 | // eslint-disable-next-line import/no-mutable-exports
7 | let warning: Warning = () => {};
8 |
9 | if (isDevelopmentEnvironment) {
10 | const printWarning: PrintWarning = (actualMessage: string) => {
11 | const message = `Warning: ${actualMessage}`;
12 | if (typeof console !== "undefined") {
13 | console.error(message);
14 | }
15 |
16 | try {
17 | // --- Welcome to debugging React ---
18 | // This error was thrown as a convenience so that you can use this stack
19 | // to find the call site that caused this warning to fire.
20 | throw new Error(message);
21 | // eslint-disable-next-line no-empty
22 | } catch {}
23 | };
24 |
25 | warning = function (condition: boolean, actualMessage: string) {
26 | if (!condition) {
27 | printWarning(actualMessage);
28 | }
29 | };
30 | }
31 |
32 | export { warning };
33 |
--------------------------------------------------------------------------------
/packages/rooks/src/index-standalone.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/namespace */
2 | /* eslint-disable guard-for-in */
3 | import * as secondary from ".";
4 |
5 | const rooks: {
6 | [key: string]: unknown;
7 | } = {};
8 |
9 | for (const key in secondary) {
10 | rooks[key] = (
11 | secondary as {
12 | [key: string]: unknown;
13 | }
14 | )[key] as unknown;
15 | }
16 |
17 | export default rooks;
18 |
--------------------------------------------------------------------------------
/packages/rooks/src/jest.setup.ts:
--------------------------------------------------------------------------------
1 | import "@testing-library/jest-dom";
2 |
3 | // setupTests.ts
4 | class SpeechSynthesisUtteranceMock {
5 | text: string;
6 | lang: string;
7 | voiceURI: string;
8 | volume: number;
9 | rate: number;
10 | pitch: number;
11 | onstart: (() => void) | null;
12 | onend: (() => void) | null;
13 | onerror: (() => void) | null;
14 | onpause: (() => void) | null;
15 | onresume: (() => void) | null;
16 | onboundary: (() => void) | null;
17 |
18 | constructor() {
19 | this.text = "";
20 | this.lang = "";
21 | this.voiceURI = "";
22 | this.volume = 1;
23 | this.rate = 1;
24 | this.pitch = 1;
25 | this.onstart = null;
26 | this.onend = null;
27 | this.onerror = null;
28 | this.onpause = null;
29 | this.onresume = null;
30 | this.onboundary = null;
31 | }
32 | }
33 |
34 | // Add the mock implementation to the global scope
35 | (global as any).SpeechSynthesisUtterance = SpeechSynthesisUtteranceMock;
36 |
--------------------------------------------------------------------------------
/packages/rooks/src/types/index-value.ts:
--------------------------------------------------------------------------------
1 | export type OptionalIndexValue = { index?: number; value?: T };
2 | export type OptionalIndicesValues = {
3 | indices?: number[];
4 | values?: T[];
5 | };
6 |
--------------------------------------------------------------------------------
/packages/rooks/src/types/types.ts:
--------------------------------------------------------------------------------
1 | import type { ExcludeFunction } from "./utils";
2 |
3 | export type UseUndoStateOptions = {
4 | maxSize: number;
5 | };
6 | type UseUndoStatePushFunctionArgumentsCallback = (currentValue: T) => T;
7 | export type UseUndoStatePushFunction = (
8 | argument: T | UseUndoStatePushFunctionArgumentsCallback
9 | ) => void;
10 | type UndoFunction = () => void;
11 | export type UseUndoStateReturnValue = [
12 | ExcludeFunction,
13 | UseUndoStatePushFunction>,
14 | UndoFunction
15 | ];
16 |
17 | export type CallbackWithNoArguments = () => void;
18 |
19 | export type UseGeolocationReturnType = {
20 | isError: boolean;
21 | lat?: number;
22 | lng?: number;
23 | message: string;
24 | };
25 |
--------------------------------------------------------------------------------
/packages/rooks/src/types/utils.ts:
--------------------------------------------------------------------------------
1 | export type DeepNullable = {
2 | [K in keyof T]: DeepNullable | null;
3 | };
4 |
5 | export type ListenerOptions =
6 | | boolean
7 | | {
8 | capture?: boolean;
9 | once?: boolean;
10 | passive?: boolean;
11 | signal?: AbortSignal;
12 | };
13 |
14 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
15 | export type AnyFunction = (...args: any[]) => any;
16 | export type ExcludeFunction = Exclude;
17 |
--------------------------------------------------------------------------------
/packages/rooks/src/utils/doesIdentifierMatchKeyboardEvent.ts:
--------------------------------------------------------------------------------
1 | const doesIdentifierMatchKeyboardEvent = (
2 | error: KeyboardEvent,
3 | identifier: number | string
4 | ): boolean => {
5 | if (
6 | error.key === identifier ||
7 | error.code === identifier ||
8 | error.keyCode === identifier ||
9 | error.which === identifier ||
10 | error.charCode === identifier
11 | ) {
12 | return true;
13 | }
14 |
15 | return false;
16 | };
17 |
18 | export { doesIdentifierMatchKeyboardEvent };
19 |
--------------------------------------------------------------------------------
/packages/rooks/src/utils/noop.ts:
--------------------------------------------------------------------------------
1 | export const noop = () => {};
2 |
--------------------------------------------------------------------------------
/packages/rooks/src/utils/utils.ts:
--------------------------------------------------------------------------------
1 | import type { MutableRefObject, Ref } from "react";
2 |
3 | export type HTMLElementOrNull = HTMLElement | null;
4 | export type RefElementOrNull = T | null;
5 |
6 | export type CallbackRef = (
7 | node: T
8 | ) => void;
9 |
10 | export type AnyRef =
11 | | CallbackRef
12 | | MutableRefObject;
13 |
14 | export type PossibleRef = Ref | undefined;
15 |
16 | type Key = string | number | symbol;
17 | export const isObject = (value: unknown): value is Record =>
18 | value !== null && typeof value === "object";
19 | // eslint-disable-next-line @typescript-eslint/ban-types
20 | export const isFunction = (value: unknown): value is Function =>
21 | typeof value === "function";
22 |
23 | export const isString = (value: unknown): value is string =>
24 | typeof value === "string";
25 | export const isBoolean = (value: unknown): value is boolean =>
26 | typeof value === "boolean";
27 | export const isNumber = (value: unknown): value is number =>
28 | typeof value === "number";
29 | export const isUndef = (value: unknown): value is undefined =>
30 | typeof value === "undefined";
31 |
--------------------------------------------------------------------------------
/packages/rooks/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": "./src",
5 | "target": "ES2017",
6 | "module": "ESNext",
7 | "moduleResolution": "Bundler",
8 | "composite": false,
9 | "sourceMap": false,
10 | "declaration": false,
11 | "declarationMap": false,
12 | "incremental": true,
13 | "paths": {
14 | "@/*": ["./*"]
15 | }
16 | },
17 | "include": ["./src/**/*.ts", "./src/**/*.tsx"],
18 | "exclude": ["./src/**/*.spec.ts", "./src/**/*.spec.tsx"]
19 | }
20 |
--------------------------------------------------------------------------------
/packages/rooks/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tsconfig/react-library.json",
3 | "compilerOptions": {
4 | "paths": {
5 | "@/*": ["*"]
6 | },
7 | "rootDir": "src",
8 | "strict": false,
9 | "module": "esnext",
10 | "jsx": "react",
11 | "target": "esnext",
12 | "baseUrl": "src",
13 | "lib": ["dom", "dom.iterable", "esnext"],
14 | "outDir": "build"
15 | },
16 | "exclude": [
17 | "node_modules",
18 | "dist",
19 | "build",
20 | "scripts",
21 | "docs",
22 | "versioned_docs",
23 | "versioned_sidebars",
24 | "src/pages",
25 | "src/css",
26 | "src/theme"
27 | ],
28 | "include": ["./e2e/**/*.ts", "./e2e/**/*.tsx"]
29 | }
30 |
--------------------------------------------------------------------------------
/packages/rooks/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/react-library.json",
3 | "include": ["src"],
4 | "exclude": ["dist", "build", "node_modules"],
5 | "compilerOptions": {
6 | "paths": {
7 | "@/*": ["./src/*"]
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/typescript-config/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @repo/typescript-config
2 |
3 | ## 0.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [#1774](https://github.com/imbhargav5/rooks/pull/1774) [`3714495`](https://github.com/imbhargav5/rooks/commit/37144959801a8c71ca9757b01656190c1ffe1218) Thanks [@imbhargav5](https://github.com/imbhargav5)! - upgrade to react 19
8 |
--------------------------------------------------------------------------------
/packages/typescript-config/base.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "compilerOptions": {
4 | "declaration": true,
5 | "declarationMap": true,
6 | "esModuleInterop": true,
7 | "incremental": false,
8 | "isolatedModules": true,
9 | "lib": ["es2022", "DOM", "DOM.Iterable"],
10 | "module": "NodeNext",
11 | "moduleDetection": "force",
12 | "moduleResolution": "NodeNext",
13 | "noUncheckedIndexedAccess": true,
14 | "resolveJsonModule": true,
15 | "skipLibCheck": true,
16 | "strict": true,
17 | "target": "ES2022"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/typescript-config/nextjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "extends": "./base.json",
4 | "compilerOptions": {
5 | "plugins": [{ "name": "next" }],
6 | "module": "ESNext",
7 | "moduleResolution": "Bundler",
8 | "allowJs": true,
9 | "jsx": "preserve",
10 | "noEmit": true
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/typescript-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@repo/typescript-config",
3 | "version": "0.1.0",
4 | "private": true,
5 | "license": "MIT",
6 | "publishConfig": {
7 | "access": "public"
8 | }
9 | }
--------------------------------------------------------------------------------
/packages/typescript-config/react-library.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "extends": "./base.json",
4 | "compilerOptions": {
5 | "jsx": "react-jsx"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "apps/*"
3 | - "packages/*"
4 |
--------------------------------------------------------------------------------
/prettier.config.cjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Options for Prettier.
3 | *
4 | * @see https://prettier.io/docs/en/options.html
5 | */
6 |
7 | module.exports = {
8 | singleQuote: true,
9 | };
10 |
--------------------------------------------------------------------------------
/scripts/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "custom",
3 | "rules": {}
4 | }
5 |
--------------------------------------------------------------------------------
/scripts/create/addHookToListAndUpdate.mjs:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import sortBy from "lodash.sortby";
3 | import { join } from "path";
4 | import pkgDir from "pkg-dir";
5 | import { dirname } from "path";
6 | import { fileURLToPath } from "url";
7 |
8 | const __filename = fileURLToPath(import.meta.url);
9 | const __dirname = dirname(__filename);
10 |
11 | export default async function addHookToListAndUpdate({
12 | name,
13 | description,
14 | category,
15 | }) {
16 | const PROJECT_ROOT = await pkgDir(__dirname);
17 | if (PROJECT_ROOT) {
18 | const listOfHooksJsonPath = join(PROJECT_ROOT, "./data/hooks-list.json");
19 | const listOfHooksJson = fs.readFileSync(listOfHooksJsonPath, "utf-8");
20 | const obj = JSON.parse(listOfHooksJson);
21 | obj.hooks.push({ name, description, category });
22 | obj.hooks = sortBy(obj.hooks, "name");
23 | fs.writeFileSync(
24 | listOfHooksJsonPath,
25 | JSON.stringify(obj, null, 2),
26 | "utf-8"
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/scripts/docs/parse-readme.ts:
--------------------------------------------------------------------------------
1 | import fromMarkdown from "mdast-util-from-markdown";
2 | import compact from "mdast-util-compact";
3 | import toMarkdown from "mdast-util-to-markdown";
4 | import normalizeHeadings from "mdast-normalize-headings";
5 | import strip from "remark-strip-badges";
6 | import remark from "remark";
7 | import behead from "remark-behead";
8 | import transformHeadings from "./transform-headings";
9 | import removeTopHeading from "./remove-top-heading";
10 | import { Buffer } from "micromark/dist/shared-types";
11 |
12 | export default function parseReadme(readmeContent: string | Buffer) {
13 | try {
14 | var tree = fromMarkdown(readmeContent);
15 | tree = compact(tree);
16 | tree = normalizeHeadings(tree);
17 | let md: any = toMarkdown(tree);
18 | md = remark()
19 | .use(strip)
20 | .use(removeTopHeading)
21 | //.use(behead, { before: "Installation", depth: 1 })
22 | //.use(transformHeadings, {before: "Installation"})
23 | .processSync(md);
24 | return md;
25 | } catch (err) {
26 | console.log("ERROR in readme parse", err);
27 | return readmeContent;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/scripts/docs/remove-top-heading.ts:
--------------------------------------------------------------------------------
1 | import { Node } from "unist";
2 | import visit, { Visitor } from "unist-util-visit";
3 |
4 | export default function stripBadges() {
5 | return transformer;
6 | }
7 |
8 | function transformer(tree: Node) {
9 | // Remove badge images, and links that include a badge image.
10 | let check: Visitor = function (node, index, parent) {
11 | var remove = false;
12 |
13 | if (node.type === "heading" && node.depth == 1) {
14 | remove = true;
15 | }
16 |
17 | if (remove === true) {
18 | parent?.children.splice(index, 1);
19 | return [visit.SKIP, index];
20 | }
21 | };
22 |
23 | visit(tree, check);
24 | }
25 |
--------------------------------------------------------------------------------
/scripts/update-all-contributors/index.mjs:
--------------------------------------------------------------------------------
1 | // This script will check for missing contributors in `.all-contributorsrc`,
2 | // and using all-contributors cli's add command to add all of them as `code` type.
3 | // If we want to add other types on a contributor, we can manually update
4 | // it using `yarn contributors:add `
5 | import { execSync } from "child_process";
6 |
7 | function getMissingContributorsList() {
8 | let stdout = execSync("yarn contributors:check").toString();
9 | let string = stdout;
10 | if (string.includes("Missing contributors in .all-contributorsrc:")) {
11 | string = string.split("Missing contributors in .all-contributorsrc:")[1];
12 | console.log(string);
13 | }
14 | if (string.includes("Unknown contributors")) {
15 | string = string.split("Unknown contributors")[0];
16 | }
17 | return string.trim().split(", ");
18 | }
19 |
20 | function addContributorsAsCoder(list) {
21 | // remove all bots first
22 | //list = list.filter((item) => !item.endsWith("[bot]"));
23 | console.log("missing contributors: ", list);
24 | for (const people of list) {
25 | console.log("adding: ", people);
26 | try {
27 | execSync(`yarn run contributors:add ${people} code`);
28 | } catch (err) {
29 | console.log("error adding user", people, err);
30 | }
31 | }
32 | }
33 |
34 | try {
35 | const list = getMissingContributorsList();
36 | addContributorsAsCoder(list);
37 | } catch (err) {
38 | console.log(err);
39 | }
40 |
--------------------------------------------------------------------------------
/static/css/custom.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017-present, Facebook, Inc.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | /* your custom css */
9 |
10 | @media only screen and (min-device-width: 360px) and (max-device-width: 736px) {
11 | }
12 |
13 | @media only screen and (min-width: 1024px) {
14 | }
15 |
16 | @media only screen and (max-width: 1023px) {
17 | }
18 |
19 | @media only screen and (min-width: 1400px) {
20 | }
21 |
22 | @media only screen and (min-width: 1500px) {
23 | }
24 |
--------------------------------------------------------------------------------
/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/static/img/favicon.ico
--------------------------------------------------------------------------------
/static/img/oss_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/static/img/oss_logo.png
--------------------------------------------------------------------------------
/static/img/rooks-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imbhargav5/rooks/1bb63d1ddcda759ff4b768e5511a3258721deefd/static/img/rooks-logo.png
--------------------------------------------------------------------------------
/template/Examples.md:
--------------------------------------------------------------------------------
1 | ### Basic Usage
2 |
--------------------------------------------------------------------------------
/template/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: %name%
3 | title: %name%
4 | sidebar_label: %name%
5 | ---
6 |
7 | ## About
8 |
9 | %description%
10 |
11 | ## Examples
12 |
13 | ```tsx
14 | import {%name%} from "rooks"
15 | export default function App() {
16 | %name%();
17 | return null
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/template/index.spec.template:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { %name% } from "@/hooks/%name%";
3 |
4 |
5 | describe("%name%", () => {
6 | it("should be defined", () => {
7 | expect.hasAssertions();
8 | expect(%name%).toBeDefined();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/template/index.template:
--------------------------------------------------------------------------------
1 | export { %name% as default } from "shared/%name%";
2 |
--------------------------------------------------------------------------------
/template/shared.template:
--------------------------------------------------------------------------------
1 | /**
2 | * %name%
3 | * @description %description%
4 | * @see {@link https://rooks.vercel.app/docs/%name%}
5 | */
6 | function %name%() {
7 | return null;
8 | }
9 |
10 | export {%name%};
11 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "tasks": {
4 | "build": {
5 | "dependsOn": ["^build"],
6 | "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
7 | },
8 | "typecheck": {
9 | "outputs": []
10 | },
11 | "lint": {
12 | "outputs": []
13 | },
14 | "dev": {
15 | "cache": false
16 | },
17 | "coverage": {
18 | "dependsOn": ["rooks#build"],
19 | "cache": false,
20 | "outputs": ["coverage/**"]
21 | },
22 | "all-checks": {
23 | "dependsOn": ["coverage", "rooks#typecheck", "lint"],
24 | "cache": false,
25 | "outputs": []
26 | },
27 | "test-hooks": {
28 | "cache": false,
29 | "outputs": []
30 | },
31 | "test": {
32 | "cache": false,
33 | "dependsOn": ["rooks#build"],
34 | "outputs": ["coverage/**", "dist/**", ".next/**"]
35 | },
36 | "start": {
37 | "cache": false,
38 | "dependsOn": ["build"],
39 | "outputs": ["dist/**", ".next/**"]
40 | },
41 | "prepare-publish": {
42 | "dependsOn": ["rooks#build"],
43 | "outputs": ["dist/**"]
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------