mirror of
https://github.com/streamich/react-use.git
synced 2026-02-01 14:37:31 +00:00
Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ef95352e4 | ||
|
|
68723a5682 | ||
|
|
e19a1141c7 | ||
|
|
756784fe15 | ||
|
|
f6b9c35833 | ||
|
|
c60dda95db | ||
|
|
b80305e6cd | ||
|
|
7ff66bcf1b | ||
|
|
7dafd4c89a | ||
|
|
9547d8e14a | ||
|
|
fa0f391ad0 | ||
|
|
54708c1964 | ||
|
|
6dbd69cc59 | ||
|
|
ad33f76dff | ||
|
|
7602956c31 | ||
|
|
7c4d69650f | ||
|
|
ea656f7e75 | ||
|
|
3eb531ac9e | ||
|
|
e1d0cd9f7f | ||
|
|
1365221792 | ||
|
|
e1aff111b0 | ||
|
|
a2028263a8 | ||
|
|
d5654ebbde | ||
|
|
388fa58d95 | ||
|
|
781bbc2003 | ||
|
|
6988a4efbc | ||
|
|
3baa63b4ac | ||
|
|
bf8f93b599 | ||
|
|
2d5e2da96a | ||
|
|
6c9f508cb7 | ||
|
|
601c3cae16 | ||
|
|
918b3dbccd | ||
|
|
05dc927a78 | ||
|
|
3fca48b2fb | ||
|
|
b54ab2b48a | ||
|
|
38255b335d | ||
|
|
f68238fb9b | ||
|
|
ba249996b6 | ||
|
|
b6e63b55ec | ||
|
|
8bc66ea1d6 | ||
|
|
8e80884485 | ||
|
|
5b5d163c2b | ||
|
|
e14d092d4d | ||
|
|
7b1ab1923a | ||
|
|
b200db9dea | ||
|
|
41b8ec359a | ||
|
|
adfb337d5b | ||
|
|
ade8d3905f | ||
|
|
ac64414bea | ||
|
|
6a9dde596a | ||
|
|
75218e45df | ||
|
|
82146f6cd4 | ||
|
|
05346481a1 | ||
|
|
06afdf7b03 | ||
|
|
ea688b0f85 | ||
|
|
3264d96fa2 | ||
|
|
e7379f0887 | ||
|
|
a6bc11996b | ||
|
|
d4e671dfca | ||
|
|
5aa843666b | ||
|
|
e27c1930da | ||
|
|
d770587296 | ||
|
|
4b6298c834 | ||
|
|
812952bb9f | ||
|
|
7a2fc183c9 | ||
|
|
325f5bd699 | ||
|
|
50857c2449 | ||
|
|
877451967f | ||
|
|
86f50475ca | ||
|
|
9b62643ee9 | ||
|
|
bb12ff23d8 | ||
|
|
5f2305fe9f | ||
|
|
6c42b006d5 | ||
|
|
3e5a816abe | ||
|
|
84aa7f3c25 | ||
|
|
e08a40fa4c | ||
|
|
6997926eea | ||
|
|
d9d8cf35c7 | ||
|
|
9256067e73 | ||
|
|
5b4073c82a | ||
|
|
6ab388f5cd | ||
|
|
1492a721ce | ||
|
|
ea287a7190 | ||
|
|
0318320e9b | ||
|
|
e292d1e879 | ||
|
|
5444b147e3 | ||
|
|
71f752da77 | ||
|
|
32e67d2855 | ||
|
|
cb5dca6ab1 | ||
|
|
e53ca94a0b | ||
|
|
500431953e | ||
|
|
70e8d817ed | ||
|
|
3e042cb2f3 | ||
|
|
d12e84fade | ||
|
|
af8d46e0c3 |
@ -1,141 +0,0 @@
|
||||
version: 2
|
||||
|
||||
refs:
|
||||
container: &container
|
||||
docker:
|
||||
- image: node:12.22.7
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- &Versions
|
||||
run:
|
||||
name: Versions
|
||||
command: node -v && npm -v && yarn -v
|
||||
- &CacheRestore
|
||||
restore_cache:
|
||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||
- &Install
|
||||
run:
|
||||
name: Install Dependencies
|
||||
command: yarn install --pure-lockfile
|
||||
- &CacheSave
|
||||
save_cache:
|
||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ./node_modules
|
||||
- &Build
|
||||
run:
|
||||
name: Build
|
||||
command: yarn build
|
||||
- &Build_Storybook
|
||||
run:
|
||||
name: Build Storybook
|
||||
command: yarn storybook:build
|
||||
- &Test
|
||||
run:
|
||||
name: Test
|
||||
command: yarn test
|
||||
- &Upload_Storybook
|
||||
run:
|
||||
name: Upload Storybook
|
||||
command: yarn storybook:upload
|
||||
- &Release
|
||||
run:
|
||||
name: Release
|
||||
command: yarn release
|
||||
- &Commit_Status_Storybook
|
||||
run:
|
||||
name: Post commit status for Storybook
|
||||
command: |
|
||||
npx cross-ci :run curl -H "'Authorization: token \${GITHUB_TOKEN}' -H 'Accept: application/vnd.github.v3+json'" \
|
||||
"'https://api.github.com/repos/\${PROJECT_OWNER}/\${PROJECT_NAME}/statuses/$CIRCLE_SHA1'" -X POST \
|
||||
-d "'{\"state\": \"success\", \"context\": \"Storybook\", \"description\": \"\${BUILD_VERSION}\", \"target_url\": \"https://$CIRCLE_BUILD_NUM-154950925-gh.circle-artifacts.com/0/root/repo/storybook-static/index.html\"}'"
|
||||
|
||||
jobs:
|
||||
all:
|
||||
<<: *container
|
||||
steps:
|
||||
- checkout
|
||||
- *Versions
|
||||
- *CacheRestore
|
||||
- *Install
|
||||
- *CacheSave
|
||||
- *Build
|
||||
- *Build_Storybook
|
||||
- *Test
|
||||
- store_artifacts:
|
||||
path: ~/repo/storybook-static
|
||||
- *Commit_Status_Storybook
|
||||
|
||||
next:
|
||||
<<: *container
|
||||
steps:
|
||||
- checkout
|
||||
- *Versions
|
||||
- *CacheRestore
|
||||
- *Install
|
||||
- *CacheSave
|
||||
- *Build
|
||||
- *Build_Storybook
|
||||
- *Test
|
||||
- store_artifacts:
|
||||
path: ~/repo/storybook-static
|
||||
- *Commit_Status_Storybook
|
||||
- run:
|
||||
name: Setup GitHub
|
||||
command: |
|
||||
git config --global user.email "streamich@gmail.com"
|
||||
git config --global user.name "streamich"
|
||||
git remote rm origin
|
||||
git remote add origin https://${GITHUB_TOKEN}@github.com/streamich/react-use
|
||||
- *Release
|
||||
|
||||
master:
|
||||
<<: *container
|
||||
steps:
|
||||
- checkout
|
||||
- *Versions
|
||||
- *CacheRestore
|
||||
- *Install
|
||||
- *CacheSave
|
||||
- *Build
|
||||
- *Build_Storybook
|
||||
- *Test
|
||||
- store_artifacts:
|
||||
path: ~/repo/storybook-static
|
||||
- *Commit_Status_Storybook
|
||||
- run:
|
||||
name: Setup GitHub
|
||||
command: |
|
||||
git config --global user.email "streamich@gmail.com"
|
||||
git config --global user.name "streamich"
|
||||
git remote rm origin
|
||||
git remote add origin https://${GITHUB_TOKEN}@github.com/streamich/react-use
|
||||
- *Upload_Storybook
|
||||
- *Release
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
all:
|
||||
jobs:
|
||||
- all:
|
||||
context: common-env-vars
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- master
|
||||
- next
|
||||
- gh-pages
|
||||
next:
|
||||
jobs:
|
||||
- next:
|
||||
context: common-env-vars
|
||||
filters:
|
||||
branches:
|
||||
only: next
|
||||
master:
|
||||
jobs:
|
||||
- master:
|
||||
context: common-env-vars
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
37
.github/workflows/check-codebase.yml
vendored
37
.github/workflows/check-codebase.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
@ -27,23 +27,23 @@ jobs:
|
||||
- name: Run build
|
||||
run: yarn build
|
||||
|
||||
storybook:
|
||||
name: Storybook
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v2
|
||||
# storybook:
|
||||
# name: Storybook
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: Check out repository
|
||||
# uses: actions/checkout@v2
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
# - name: Setup node
|
||||
# uses: actions/setup-node@v1
|
||||
# with:
|
||||
# node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
# - name: Install dependencies
|
||||
# run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run build:storybook
|
||||
run: yarn storybook:build
|
||||
# - name: Run build:storybook
|
||||
# run: yarn storybook:build
|
||||
|
||||
lint:
|
||||
name: Linting
|
||||
@ -55,7 +55,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
@ -73,10 +73,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
node: [12, 14, 16]
|
||||
exclude:
|
||||
- os: macos-latest
|
||||
node: 12
|
||||
node: [20, 22]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
21
.github/workflows/mirror.yml
vendored
Normal file
21
.github/workflows/mirror.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Push To Gitlab
|
||||
env:
|
||||
token: ${{ secrets.GITLAB_TOKEN }}
|
||||
run: |
|
||||
git config user.name "streamich"
|
||||
git config user.email "react-use+streamich@users.noreply.github.com"
|
||||
git remote add mirror "https://oauth2:${token}@gitlab.com/streamich/react-use.git"
|
||||
git push mirror master
|
||||
30
.github/workflows/release.yml
vendored
Normal file
30
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, next]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: ${{ github.event_name == 'push' && (github.event.ref == 'refs/heads/master' || github.event.ref == 'refs/heads/next') }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [22.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: yarn
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn lint
|
||||
- run: yarn test
|
||||
- run: yarn lint:types
|
||||
- run: yarn build
|
||||
- name: Semantic Release
|
||||
uses: cycjimmy/semantic-release-action@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
59
CHANGELOG.md
59
CHANGELOG.md
@ -1,3 +1,62 @@
|
||||
# [17.6.0](https://github.com/streamich/react-use/compare/v17.5.1...v17.6.0) (2024-12-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add onChange callback to useWindowSize ([ea656f7](https://github.com/streamich/react-use/commit/ea656f7e751b8366360ce2aa8238057bbbc1251a))
|
||||
* add onChange callback to useWindowSize ([3eb531a](https://github.com/streamich/react-use/commit/3eb531ac9e9e04641df29aafbd2677869cdcb085))
|
||||
|
||||
## [17.5.1](https://github.com/streamich/react-use/compare/v17.5.0...v17.5.1) (2024-07-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 bump nano-css dependency ([adfb337](https://github.com/streamich/react-use/commit/adfb337d5b11427798afc5a21c6ebdaa76212182))
|
||||
|
||||
# [17.5.0](https://github.com/streamich/react-use/compare/v17.4.4...v17.5.0) (2024-01-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add `isFirst` and `isLast` methods to `useStateList` hook ([ac64414](https://github.com/streamich/react-use/commit/ac64414bea4c8afadfb382da9fea44ee89b41e2d))
|
||||
* **pencil:** add isFirst and isLast return value to 'useStateList' ([75218e4](https://github.com/streamich/react-use/commit/75218e45dfdcdc6ea193e278cb97ceee98c00f1b))
|
||||
* **pencil:** fix with yarn lint:fix ([6a9dde5](https://github.com/streamich/react-use/commit/6a9dde596ae25c0dd2fa97b0cf354143fbc5b5ff))
|
||||
|
||||
## [17.4.4](https://github.com/streamich/react-use/compare/v17.4.3...v17.4.4) (2024-01-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* typo in example ([0534648](https://github.com/streamich/react-use/commit/05346481a15a321b13838eead0bda3024b0d163f))
|
||||
|
||||
## [17.4.3](https://github.com/streamich/react-use/compare/v17.4.2...v17.4.3) (2024-01-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update useMedia hook to use recommended approach of MDN ([e7379f0](https://github.com/streamich/react-use/commit/e7379f088787cbf9274c1fc21d36061f04855e4c))
|
||||
|
||||
## [17.4.2](https://github.com/streamich/react-use/compare/v17.4.1...v17.4.2) (2023-12-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correct peer dependencies ([d770587](https://github.com/streamich/react-use/commit/d77058729654397b68b251e8211bf0edc0b4ed50))
|
||||
|
||||
## [17.4.1](https://github.com/streamich/react-use/compare/v17.4.0...v17.4.1) (2023-11-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 bump nano-css version ([812952b](https://github.com/streamich/react-use/commit/812952bb9ff004a844ec4285ad6c65d39597b11c))
|
||||
|
||||
# [17.4.0](https://github.com/streamich/react-use/compare/v17.3.3...v17.4.0) (2022-05-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add usePinchZoom sensor hook ([3e042cb](https://github.com/streamich/react-use/commit/3e042cb2f3022349a53199b5cc5c380e3ebd9975))
|
||||
|
||||
## [17.3.3](https://github.com/streamich/react-use/compare/v17.3.2...v17.3.3) (2022-05-20)
|
||||
|
||||
|
||||
|
||||
12
README.md
12
README.md
@ -1,10 +1,3 @@
|
||||
<div align="center">
|
||||
<a href="https://www.kickstarter.com/projects/aleks-p/multiplayer-collaborative-editing-database">
|
||||
Collaborative editing for your app. <strong>Support on Kickstarter!</strong>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div align="center">
|
||||
<h1>
|
||||
<br/>
|
||||
@ -77,6 +70,7 @@
|
||||
- [`useMeasure`](./docs/useMeasure.md) and [`useSize`](./docs/useSize.md) — tracks an HTML element's dimensions. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemeasure--demo)
|
||||
- [`createBreakpoint`](./docs/createBreakpoint.md) — tracks `innerWidth`
|
||||
- [`useScrollbarWidth`](./docs/useScrollbarWidth.md) — detects browser's native scrollbars width. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usescrollbarwidth--demo)
|
||||
- [`usePinchZoom`](./docs/usePinchZoom.md) — tracks pointer events to detect pinch zoom in and out status. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usePinchZoom--demo)
|
||||
<br/>
|
||||
<br/>
|
||||
- [**UI**](./docs/UI.md)
|
||||
@ -128,8 +122,8 @@
|
||||
- [`useMount`](./docs/useMount.md) — calls `mount` callbacks.
|
||||
- [`useUnmount`](./docs/useUnmount.md) — calls `unmount` callbacks.
|
||||
- [`useUpdateEffect`](./docs/useUpdateEffect.md) — run an `effect` only on updates.
|
||||
- [`useIsomorphicLayoutEffect`](./docs/useIsomorphicLayoutEffect.md) — `useLayoutEffect` that does not show warning when server-side rendering.
|
||||
- [`useDeepCompareEffect`](./docs/useDeepCompareEffect.md), [`useShallowCompareEffect`](./docs/useShallowCompareEffect.md), and [`useCustomCompareEffect`](./docs/useCustomCompareEffect.md) — run an `effect` depending on deep comparison of its dependencies
|
||||
- [`useIsomorphicLayoutEffect`](./docs/useIsomorphicLayoutEffect.md) — `useLayoutEffect` that that works on server.
|
||||
- [`useDeepCompareEffect`](./docs/useDeepCompareEffect.md), [`useShallowCompareEffect`](./docs/useShallowCompareEffect.md), and [`useCustomCompareEffect`](./docs/useCustomCompareEffect.md)
|
||||
<br/>
|
||||
<br/>
|
||||
- [**State**](./docs/State.md)
|
||||
|
||||
13
SECURITY.md
Normal file
13
SECURITY.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We release patches for security vulnerabilities. The latest major version
|
||||
will support security patches.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report (suspected) security vulnerabilities to
|
||||
**[streamich@gmail.com](mailto:streamich@gmail.com)**. We will try to respond
|
||||
within 48 hours. If the issue is confirmed, we will release a patch as soon
|
||||
as possible depending on complexity.
|
||||
36
docs/usePinchZoom.md
Normal file
36
docs/usePinchZoom.md
Normal file
@ -0,0 +1,36 @@
|
||||
# `usePinchZoom`
|
||||
|
||||
React sensor hook that tracks the changes in pointer touch events and detects value of pinch difference and tell if user is zooming in or out.
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import { usePinchZoom } from "react-use";
|
||||
|
||||
const Demo = () => {
|
||||
const [scale, setState] = useState(1);
|
||||
const scaleRef = useRef();
|
||||
const { zoomingState, pinchState } = usePinchZoom(scaleRef);
|
||||
|
||||
useEffect(() => {
|
||||
if (zoomingState === "ZOOM_IN") {
|
||||
// perform zoom in scaling
|
||||
setState(scale + 0.1)
|
||||
} else if (zoomingState === "ZOOM_OUT") {
|
||||
// perform zoom out in scaling
|
||||
setState(scale - 0.1)
|
||||
}
|
||||
}, [zoomingState]);
|
||||
|
||||
return (
|
||||
<div ref={scaleRef}>
|
||||
<img
|
||||
src="https://www.olympus-imaging.co.in/content/000107506.jpg"
|
||||
style={{
|
||||
zoom: scale,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
@ -4,16 +4,22 @@ React state hook that tracks a [Set](https://developer.mozilla.org/en-US/docs/We
|
||||
|
||||
## Usage
|
||||
|
||||
What is the difference between the "clear()" method and the "reset()" method?
|
||||
|
||||
The "reset()" method returns the "Set" to the initial value passed during "useSet
|
||||
The "clear()" method completely empties the "Set".
|
||||
|
||||
```jsx
|
||||
import {useSet} from 'react-use';
|
||||
|
||||
const Demo = () => {
|
||||
const [set, { add, has, remove, toggle, reset }] = useSet(new Set(['hello']));
|
||||
const [set, { add, has, remove, toggle, reset, clear }] = useSet(new Set(['hello']));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => add(String(Date.now()))}>Add</button>
|
||||
<button onClick={() => reset()}>Reset</button>
|
||||
<button onClick={() => clear()}>Clear</button>
|
||||
<button onClick={() => remove('hello')} disabled={!has('hello')}>
|
||||
Remove 'hello'
|
||||
</button>
|
||||
|
||||
@ -15,7 +15,7 @@ const Demo = () => {
|
||||
<div>
|
||||
<div ref={ref} style={{ position: 'relative' }}>
|
||||
<p style={{ textAlign: 'center', color: isSliding ? 'red' : 'green' }}>
|
||||
{Math.round(state.value * 100)}%
|
||||
{Math.round(value * 100)}%
|
||||
</p>
|
||||
<div style={{ position: 'absolute', left: pos }}>🎚</div>
|
||||
</div>
|
||||
|
||||
@ -12,14 +12,14 @@ import { useRef } from 'react';
|
||||
const stateSet = ['first', 'second', 'third', 'fourth', 'fifth'];
|
||||
|
||||
const Demo = () => {
|
||||
const { state, prev, next, setStateAt, setState, currentIndex } = useStateList(stateSet);
|
||||
const { state, prev, next, setStateAt, setState, currentIndex, isFirst, isLast } = useStateList(stateSet);
|
||||
const indexInput = useRef<HTMLInputElement>(null);
|
||||
const stateInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<pre>
|
||||
{state} [index: {currentIndex}]
|
||||
{state} [index: {currentIndex}], [isFirst: {isFirst}], [isLast: {isLast}]
|
||||
</pre>
|
||||
<button onClick={() => prev()}>prev</button>
|
||||
<br />
|
||||
@ -38,7 +38,7 @@ const Demo = () => {
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
const { state, currentIndex, prev, next, setStateAt, setState } = useStateList<T>(stateSet: T[] = []);
|
||||
const { state, currentIndex, prev, next, setStateAt, setState, isFirst, isLast } = useStateList<T>(stateSet: T[] = []);
|
||||
```
|
||||
|
||||
If `stateSet` changed, became shorter than before and `currentIndex` left in shrunk gap - the last element of list will be taken as current.
|
||||
@ -48,5 +48,7 @@ If `stateSet` changed, became shorter than before and `currentIndex` left in shr
|
||||
- **`prev()`**_`: void`_ — switches state to the previous one. If first element selected it will switch to the last one;
|
||||
- **`next()`**_`: void`_ — switches state to the next one. If last element selected it will switch to the first one;
|
||||
- **`setStateAt(newIndex: number)`**_`: void`_ — set the arbitrary state by index. Indexes are looped, and can be negative.
|
||||
_4ex:_ if list contains 5 elements, attempt to set index 9 will bring use to the 5th element, in case of negative index it will start counting from the right, so -17 will bring us to the 4th element.
|
||||
_4ex:_ if list contains 5 elements, attempt to set index 9 will bring use to the 5th element, in case of negative index it will start counting from the right, so -17 will bring us to the 4th element.
|
||||
- **`setState(state: T)`**_`: void`_ — set the arbitrary state value that exists in `stateSet`. _In case new state does not exists in `stateSet` an Error will be thrown._
|
||||
- **`isFirst`**_`: boolean`_ — `true` if current state is the first one.
|
||||
- **`isLast`**_`: boolean`_ — `true` if current state is the last one.
|
||||
|
||||
@ -19,3 +19,18 @@ const Demo = () => {
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```js
|
||||
useWindowSize(options);
|
||||
```
|
||||
|
||||
- `initialWidth` — Initial width value for non-browser environments.
|
||||
- `initialHeight` — Initial height value for non-browser environments.
|
||||
- `onChange` — Callback function triggered when the window size changes.
|
||||
|
||||
## Related hooks
|
||||
|
||||
- [useSize](./useSize.md)
|
||||
- [useMeasure](./useMeasure.md)
|
||||
76
package.json
76
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-use",
|
||||
"version": "17.3.3",
|
||||
"version": "17.6.0",
|
||||
"description": "Collection of React Hooks",
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
@ -53,7 +53,7 @@
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-shallow-equal": "^1.0.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"nano-css": "^5.3.1",
|
||||
"nano-css": "^5.6.2",
|
||||
"react-universal-interface": "^0.6.2",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.1.0",
|
||||
@ -63,67 +63,67 @@
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.16.0",
|
||||
"@babel/core": "7.28.3",
|
||||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||
"@babel/preset-env": "7.16.4",
|
||||
"@babel/preset-react": "7.16.0",
|
||||
"@babel/preset-typescript": "7.16.0",
|
||||
"@semantic-release/changelog": "5.0.1",
|
||||
"@semantic-release/git": "9.0.1",
|
||||
"@semantic-release/npm": "7.1.3",
|
||||
"@babel/preset-env": "7.28.3",
|
||||
"@babel/preset-react": "7.27.1",
|
||||
"@babel/preset-typescript": "7.27.1",
|
||||
"@semantic-release/changelog": "6.0.3",
|
||||
"@semantic-release/git": "10.0.1",
|
||||
"@semantic-release/npm": "12.0.2",
|
||||
"@shopify/jest-dom-mocks": "2.11.7",
|
||||
"@storybook/addon-actions": "6.4.9",
|
||||
"@storybook/addon-knobs": "6.2.9",
|
||||
"@storybook/addon-knobs": "6.4.0",
|
||||
"@storybook/addon-notes": "5.3.21",
|
||||
"@storybook/addon-options": "5.3.21",
|
||||
"@storybook/react": "6.4.9",
|
||||
"@testing-library/react": "12.1.2",
|
||||
"@testing-library/react": "12.1.5",
|
||||
"@testing-library/react-hooks": "7.0.2",
|
||||
"@types/jest": "27.0.3",
|
||||
"@types/jest": "27.5.2",
|
||||
"@types/react": "17.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.6.0",
|
||||
"@typescript-eslint/parser": "5.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.62.0",
|
||||
"@typescript-eslint/parser": "5.62.0",
|
||||
"babel-core": "6.26.3",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-loader": "8.2.3",
|
||||
"babel-loader": "8.4.1",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"eslint": "8.4.1",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-prettier": "8.10.2",
|
||||
"eslint-config-react-app": "6.0.0",
|
||||
"eslint-plugin-flowtype": "8.0.3",
|
||||
"eslint-plugin-import": "2.25.3",
|
||||
"eslint-plugin-jsx-a11y": "6.5.1",
|
||||
"eslint-plugin-prettier": "4.0.0",
|
||||
"eslint-plugin-react": "7.27.1",
|
||||
"eslint-plugin-react-hooks": "4.3.0",
|
||||
"fork-ts-checker-webpack-plugin": "6.5.0",
|
||||
"gh-pages": "3.2.3",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||
"eslint-plugin-prettier": "4.2.5",
|
||||
"eslint-plugin-react": "7.37.5",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "6.5.3",
|
||||
"gh-pages": "5.0.0",
|
||||
"husky": "7.0.4",
|
||||
"jest": "26.6.3",
|
||||
"jest-localstorage-mock": "2.4.18",
|
||||
"keyboardjs": "2.6.4",
|
||||
"lint-staged": "12.1.2",
|
||||
"jest-localstorage-mock": "2.4.26",
|
||||
"keyboardjs": "2.7.0",
|
||||
"lint-staged": "12.5.0",
|
||||
"markdown-loader": "6.0.0",
|
||||
"prettier": "2.3.0",
|
||||
"raf-stub": "3.0.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-frame-component": "5.2.1",
|
||||
"react-spring": "9.3.2",
|
||||
"react-frame-component": "5.2.7",
|
||||
"react-spring": "9.7.5",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"rebound": "0.1.0",
|
||||
"redux-logger": "3.0.6",
|
||||
"redux-thunk": "2.4.1",
|
||||
"redux-thunk": "2.4.2",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "7.4.0",
|
||||
"semantic-release": "17.4.7",
|
||||
"rxjs": "7.8.2",
|
||||
"semantic-release": "24.2.7",
|
||||
"ts-jest": "26.5.6",
|
||||
"ts-loader": "~8.2.0",
|
||||
"ts-node": "10.4.0",
|
||||
"ts-loader": "8.4.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "4.1.5"
|
||||
},
|
||||
"config": {
|
||||
@ -157,8 +157,8 @@
|
||||
]
|
||||
},
|
||||
"volta": {
|
||||
"node": "14.18.2",
|
||||
"yarn": "1.22.17"
|
||||
"node": "14.21.3",
|
||||
"yarn": "1.22.22"
|
||||
},
|
||||
"collective": {
|
||||
"type": "opencollective",
|
||||
|
||||
@ -109,6 +109,7 @@ export { useMultiStateValidator } from './useMultiStateValidator';
|
||||
export { default as useWindowScroll } from './useWindowScroll';
|
||||
export { default as useWindowSize } from './useWindowSize';
|
||||
export { default as useMeasure } from './useMeasure';
|
||||
export { default as usePinchZoom } from './usePinchZoom';
|
||||
export { useRendersCount } from './useRendersCount';
|
||||
export { useFirstMountState } from './useFirstMountState';
|
||||
export { default as useSet } from './useSet';
|
||||
|
||||
@ -34,12 +34,12 @@ const useMedia = (query: string, defaultState?: boolean) => {
|
||||
setState(!!mql.matches);
|
||||
};
|
||||
|
||||
mql.addListener(onChange);
|
||||
mql.addEventListener('change', onChange);
|
||||
setState(mql.matches);
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
mql.removeListener(onChange);
|
||||
mql.removeEventListener('change', onChange);
|
||||
};
|
||||
}, [query]);
|
||||
|
||||
|
||||
109
src/usePinchZoom.ts
Normal file
109
src/usePinchZoom.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { RefObject, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
export type CacheRef = {
|
||||
prevDiff: number;
|
||||
evCache: Array<PointerEvent>;
|
||||
};
|
||||
|
||||
export enum ZoomState {
|
||||
'ZOOMING_IN' = 'ZOOMING_IN',
|
||||
'ZOOMING_OUT' = 'ZOOMING_OUT',
|
||||
}
|
||||
|
||||
export type ZoomStateType = ZoomState.ZOOMING_IN | ZoomState.ZOOMING_OUT;
|
||||
|
||||
const usePinchZoom = (ref: RefObject<HTMLElement>) => {
|
||||
const cacheRef = useMemo<CacheRef>(
|
||||
() => ({
|
||||
evCache: [],
|
||||
prevDiff: -1,
|
||||
}),
|
||||
[ref.current]
|
||||
);
|
||||
|
||||
const [zoomingState, setZoomingState] = useState<[ZoomStateType, number]>();
|
||||
|
||||
const pointermove_handler = (ev: PointerEvent) => {
|
||||
// This function implements a 2-pointer horizontal pinch/zoom gesture.
|
||||
//
|
||||
// If the distance between the two pointers has increased (zoom in),
|
||||
// the target element's background is changed to 'pink' and if the
|
||||
// distance is decreasing (zoom out), the color is changed to 'lightblue'.
|
||||
//
|
||||
// This function sets the target element's border to 'dashed' to visually
|
||||
// indicate the pointer's target received a move event.
|
||||
// Find this event in the cache and update its record with this event
|
||||
for (let i = 0; i < cacheRef.evCache.length; i++) {
|
||||
if (ev.pointerId == cacheRef.evCache[i].pointerId) {
|
||||
cacheRef.evCache[i] = ev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If two pointers are down, check for pinch gestures
|
||||
if (cacheRef.evCache.length == 2) {
|
||||
// console.log(prevDiff)
|
||||
// Calculate the distance between the two pointers
|
||||
const curDiff = Math.abs(cacheRef.evCache[0].clientX - cacheRef.evCache[1].clientX);
|
||||
|
||||
if (cacheRef.prevDiff > 0) {
|
||||
if (curDiff > cacheRef.prevDiff) {
|
||||
// The distance between the two pointers has increased
|
||||
setZoomingState([ZoomState.ZOOMING_IN, curDiff]);
|
||||
}
|
||||
if (curDiff < cacheRef.prevDiff) {
|
||||
// The distance between the two pointers has decreased
|
||||
setZoomingState([ZoomState.ZOOMING_OUT, curDiff]);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the distance for the next move event
|
||||
cacheRef.prevDiff = curDiff;
|
||||
}
|
||||
};
|
||||
|
||||
const pointerdown_handler = (ev: PointerEvent) => {
|
||||
// The pointerdown event signals the start of a touch interaction.
|
||||
// This event is cached to support 2-finger gestures
|
||||
cacheRef.evCache.push(ev);
|
||||
// console.log('pointerDown', ev);
|
||||
};
|
||||
|
||||
const pointerup_handler = (ev: PointerEvent) => {
|
||||
// Remove this pointer from the cache and reset the target's
|
||||
// background and border
|
||||
remove_event(ev);
|
||||
|
||||
// If the number of pointers down is less than two then reset diff tracker
|
||||
if (cacheRef.evCache.length < 2) {
|
||||
cacheRef.prevDiff = -1;
|
||||
}
|
||||
};
|
||||
|
||||
const remove_event = (ev: PointerEvent) => {
|
||||
// Remove this event from the target's cache
|
||||
for (let i = 0; i < cacheRef.evCache.length; i++) {
|
||||
if (cacheRef.evCache[i].pointerId == ev.pointerId) {
|
||||
cacheRef.evCache.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (ref?.current) {
|
||||
ref.current.onpointerdown = pointerdown_handler;
|
||||
ref.current.onpointermove = pointermove_handler;
|
||||
ref.current.onpointerup = pointerup_handler;
|
||||
ref.current.onpointercancel = pointerup_handler;
|
||||
ref.current.onpointerout = pointerup_handler;
|
||||
ref.current.onpointerleave = pointerup_handler;
|
||||
}
|
||||
}, [ref?.current]);
|
||||
|
||||
return zoomingState
|
||||
? { zoomingState: zoomingState[0], pinchState: zoomingState[1] }
|
||||
: { zoomingState: null, pinchState: 0 };
|
||||
};
|
||||
|
||||
export default usePinchZoom;
|
||||
@ -5,6 +5,7 @@ export interface StableActions<K> {
|
||||
remove: (key: K) => void;
|
||||
toggle: (key: K) => void;
|
||||
reset: () => void;
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export interface Actions<K> extends StableActions<K> {
|
||||
@ -25,7 +26,7 @@ const useSet = <K>(initialSet = new Set<K>()): [Set<K>, Actions<K>] => {
|
||||
: new Set([...Array.from(prevSet), item])
|
||||
);
|
||||
|
||||
return { add, remove, toggle, reset: () => setSet(initialSet) };
|
||||
return { add, remove, toggle, reset: () => setSet(initialSet), clear: () => setSet(new Set()) };
|
||||
}, [setSet]);
|
||||
|
||||
const utils = {
|
||||
|
||||
@ -10,6 +10,8 @@ export interface UseStateListReturn<T> {
|
||||
setState: (state: T) => void;
|
||||
next: () => void;
|
||||
prev: () => void;
|
||||
isFirst: boolean;
|
||||
isLast: boolean;
|
||||
}
|
||||
|
||||
export default function useStateList<T>(stateSet: T[] = []): UseStateListReturn<T> {
|
||||
@ -68,6 +70,8 @@ export default function useStateList<T>(stateSet: T[] = []): UseStateListReturn<
|
||||
return {
|
||||
state: stateSet[index.current],
|
||||
currentIndex: index.current,
|
||||
isFirst: index.current === 0,
|
||||
isLast: index.current === stateSet.length - 1,
|
||||
...actions,
|
||||
};
|
||||
}
|
||||
|
||||
@ -3,29 +3,52 @@ import { useEffect } from 'react';
|
||||
import useRafState from './useRafState';
|
||||
import { isBrowser, off, on } from './misc/util';
|
||||
|
||||
const useWindowSize = (initialWidth = Infinity, initialHeight = Infinity) => {
|
||||
// Define the type for options that can be passed to the hook
|
||||
interface Options {
|
||||
initialWidth?: number; // Initial width of the window (Default value is Infinity)
|
||||
initialHeight?: number; // Initial height of the window (Default value is Infinity)
|
||||
onChange?: (width: number, height: number) => void; // Callback function to execute on window resize (optional)
|
||||
}
|
||||
|
||||
const useWindowSize = ({
|
||||
initialWidth = Infinity,
|
||||
initialHeight = Infinity,
|
||||
onChange,
|
||||
}: Options = {}) => {
|
||||
// Use the useRafState hook to maintain the current window size (width and height)
|
||||
const [state, setState] = useRafState<{ width: number; height: number }>({
|
||||
width: isBrowser ? window.innerWidth : initialWidth,
|
||||
height: isBrowser ? window.innerHeight : initialHeight,
|
||||
});
|
||||
|
||||
useEffect((): (() => void) | void => {
|
||||
// Only run the effect on the browser (to avoid issues with SSR)
|
||||
if (isBrowser) {
|
||||
const handler = () => {
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
|
||||
// Update the state with the new window size
|
||||
setState({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
|
||||
// If an onChange callback is provided, call it with the new dimensions
|
||||
if (onChange) onChange(width, height);
|
||||
};
|
||||
|
||||
// Add event listener for the resize event
|
||||
on(window, 'resize', handler);
|
||||
|
||||
// Cleanup function to remove the event listener when the component is unmounted (it's for performance optimization)
|
||||
return () => {
|
||||
off(window, 'resize', handler);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Return the current window size (width and height)
|
||||
return state;
|
||||
};
|
||||
|
||||
|
||||
38
stories/usePinchZoom.story.tsx
Normal file
38
stories/usePinchZoom.story.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { usePinchZoom } from '../src';
|
||||
import { ZoomState } from '../src/usePinchZoom';
|
||||
import ShowDocs from './util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const [scale, setState] = useState(1);
|
||||
const scaleRef = useRef();
|
||||
const { zoomingState, pinchState } = usePinchZoom(scaleRef);
|
||||
|
||||
useEffect(() => {
|
||||
if (zoomingState === ZoomState.ZOOMING_IN) {
|
||||
// perform zoom in scaling
|
||||
setState(scale + 0.1);
|
||||
} else if (zoomingState === ZoomState.ZOOMING_OUT) {
|
||||
// perform zoom out in scaling
|
||||
setState(scale - 0.1);
|
||||
}
|
||||
}, [zoomingState, pinchState]);
|
||||
|
||||
return (
|
||||
<div ref={scaleRef}>
|
||||
<img
|
||||
src="https://www.olympus-imaging.co.in/content/000107506.jpg"
|
||||
style={{
|
||||
zoom: scale,
|
||||
}}
|
||||
alt="scale img"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf('Sensors/usePinchZoom', module)
|
||||
.add('Docs', () => <ShowDocs md={require('../docs/usePinchZoom.md')} />)
|
||||
.add('Default', () => <Demo />);
|
||||
@ -4,12 +4,13 @@ import { useSet } from '../src';
|
||||
import ShowDocs from './util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const [set, { add, has, remove, reset, toggle }] = useSet(new Set(['hello']));
|
||||
const [set, { add, has, remove, reset, clear, toggle }] = useSet(new Set(['hello']));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => add(String(Date.now()))}>Add</button>
|
||||
<button onClick={() => reset()}>Reset</button>
|
||||
<button onClick={() => clear()}>Clear</button>
|
||||
<button onClick={() => remove('hello')} disabled={!has('hello')}>
|
||||
Remove 'hello'
|
||||
</button>
|
||||
|
||||
@ -7,14 +7,15 @@ import ShowDocs from './util/ShowDocs';
|
||||
const stateSet = ['first', 'second', 'third', 'fourth', 'fifth'];
|
||||
|
||||
const Demo = () => {
|
||||
const { state, prev, next, setStateAt, setState, currentIndex } = useStateList(stateSet);
|
||||
const { state, prev, next, setStateAt, setState, currentIndex, isFirst, isLast } =
|
||||
useStateList(stateSet);
|
||||
const indexInput = useRef<HTMLInputElement>(null);
|
||||
const stateInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<pre>
|
||||
{state} [index: {currentIndex}]
|
||||
{state} [index: {currentIndex}], [isFirst: {isFirst}], [isLast: {isLast}]
|
||||
</pre>
|
||||
<button onClick={() => prev()}>prev</button>
|
||||
<br />
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
import { useWindowSize } from '../src';
|
||||
import { action } from '@storybook/addon-actions'; // Import addon-actions
|
||||
import ShowDocs from './util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const { width, height } = useWindowSize();
|
||||
const { width, height } = useWindowSize({
|
||||
// Log the resize event to the Storybook actions panel
|
||||
onChange: action('window resize'),
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -4,8 +4,8 @@ import { useMedia } from '../src';
|
||||
|
||||
const createMockMediaMatcher = (matches: Record<string, boolean>) => (qs: string) => ({
|
||||
matches: matches[qs] ?? false,
|
||||
addListener: () => {},
|
||||
removeListener: () => {},
|
||||
addEventListener: () => {},
|
||||
removeEventListener: () => {},
|
||||
});
|
||||
|
||||
describe('useMedia', () => {
|
||||
|
||||
@ -14,6 +14,7 @@ it('should init set and utils', () => {
|
||||
remove: expect.any(Function),
|
||||
toggle: expect.any(Function),
|
||||
reset: expect.any(Function),
|
||||
clear: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
@ -145,10 +146,21 @@ it('should reset to initial set provided', () => {
|
||||
expect(result.current[0]).toEqual(new Set([1]));
|
||||
});
|
||||
|
||||
it('should be empty', () => {
|
||||
const { result } = setUp(new Set([1]));
|
||||
const [, utils] = result.current;
|
||||
|
||||
act(() => {
|
||||
utils.clear();
|
||||
});
|
||||
|
||||
expect(result.current[0]).toEqual(new Set([]));
|
||||
});
|
||||
|
||||
it('should memoized its utils methods', () => {
|
||||
const { result } = setUp(new Set(['a', 'b']));
|
||||
const [, utils] = result.current;
|
||||
const { add, remove, reset, toggle } = utils;
|
||||
const { add, remove, reset, clear, toggle } = utils;
|
||||
|
||||
act(() => {
|
||||
add('foo');
|
||||
@ -158,4 +170,5 @@ it('should memoized its utils methods', () => {
|
||||
expect(result.current[1].remove).toBe(remove);
|
||||
expect(result.current[1].toggle).toBe(toggle);
|
||||
expect(result.current[1].reset).toBe(reset);
|
||||
expect(result.current[1].clear).toBe(clear);
|
||||
});
|
||||
|
||||
@ -20,6 +20,8 @@ describe('useStateList', () => {
|
||||
next: expect.any(Function),
|
||||
setStateAt: expect.any(Function),
|
||||
setState: expect.any(Function),
|
||||
isFirst: expect.any(Boolean),
|
||||
isLast: expect.any(Boolean),
|
||||
});
|
||||
});
|
||||
|
||||
@ -27,6 +29,17 @@ describe('useStateList', () => {
|
||||
expect(getHook().result.current.state).toBe('a');
|
||||
});
|
||||
|
||||
it('should return isFirst on init', () => {
|
||||
expect(getHook().result.current.isFirst).toBe(true);
|
||||
});
|
||||
|
||||
it('should return isLast when on last state', () => {
|
||||
const hook = getHook();
|
||||
act(() => hook.result.current.setStateAt(2));
|
||||
|
||||
expect(hook.result.current.isLast).toBe(true);
|
||||
});
|
||||
|
||||
describe('setState()', () => {
|
||||
it('should set state value if it exists in states list', () => {
|
||||
const hook = getHook();
|
||||
|
||||
@ -21,8 +21,8 @@ describe('useWindowSize', () => {
|
||||
expect(useWindowSize).toBeDefined();
|
||||
});
|
||||
|
||||
function getHook(...args) {
|
||||
return renderHook(() => useWindowSize(...args));
|
||||
function getHook(options?: any) {
|
||||
return renderHook(() => useWindowSize(options));
|
||||
}
|
||||
|
||||
function triggerResize(dimension: 'width' | 'height', value: number) {
|
||||
@ -44,7 +44,7 @@ describe('useWindowSize', () => {
|
||||
});
|
||||
|
||||
it('should use passed parameters as initial values in case of non-browser use', () => {
|
||||
const hook = getHook(1, 1);
|
||||
const hook = getHook({ initialWidth: 1, initialHeight: 1 });
|
||||
|
||||
expect(hook.result.current.height).toBe(isBrowser ? window.innerHeight : 1);
|
||||
expect(hook.result.current.width).toBe(isBrowser ? window.innerWidth : 1);
|
||||
@ -85,4 +85,27 @@ describe('useWindowSize', () => {
|
||||
|
||||
expect(hook.result.current.width).toBe(2048);
|
||||
});
|
||||
|
||||
it('should call onChange callback on window resize', () => {
|
||||
const onChange = jest.fn();
|
||||
getHook({ onChange });
|
||||
|
||||
act(() => {
|
||||
triggerResize('width', 720);
|
||||
triggerResize('height', 480);
|
||||
requestAnimationFrame.step();
|
||||
});
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith(720, 480);
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
|
||||
act(() => {
|
||||
triggerResize('width', 1920);
|
||||
triggerResize('height', 1080);
|
||||
requestAnimationFrame.step();
|
||||
});
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith(1920, 1080);
|
||||
expect(onChange).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user