@react-hookz/web
Advanced tools
Comparing version 1.20.4 to 1.21.0
@@ -0,1 +1,8 @@ | ||
# [1.21.0](https://github.com/react-hookz/web/compare/v1.20.4...v1.21.0) (2021-05-25) | ||
### Features | ||
* new hook `useResizeObserver` ([#67](https://github.com/react-hookz/web/issues/67)) ([ccf2c26](https://github.com/react-hookz/web/commit/ccf2c268636f66194f96ef8f232a1fb46b6af056)) | ||
## [1.20.4](https://github.com/react-hookz/web/compare/v1.20.3...v1.20.4) (2021-05-24) | ||
@@ -2,0 +9,0 @@ |
@@ -20,1 +20,2 @@ export { useDebounceCallback } from './useDebounceCallback'; | ||
export { useSessionStorageValue } from './useSessionStorageValue'; | ||
export { useResizeObserver, IUseResizeObserverCallback } from './useResizeObserver'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.useSessionStorageValue = exports.useLocalStorageValue = exports.useSyncedRef = exports.useNetworkState = exports.useToggle = exports.useSafeState = exports.usePrevious = exports.useMediatedState = exports.useUpdateEffect = exports.useUnmountEffect = exports.useRerender = exports.useMountEffect = exports.useIsomorphicLayoutEffect = exports.useIsMounted = exports.useFirstMountState = exports.useConditionalUpdateEffect = exports.useConditionalEffect = exports.useRafCallback = exports.useDebounceCallback = void 0; | ||
exports.useResizeObserver = exports.useSessionStorageValue = exports.useLocalStorageValue = exports.useSyncedRef = exports.useNetworkState = exports.useToggle = exports.useSafeState = exports.usePrevious = exports.useMediatedState = exports.useUpdateEffect = exports.useUnmountEffect = exports.useRerender = exports.useMountEffect = exports.useIsomorphicLayoutEffect = exports.useIsMounted = exports.useFirstMountState = exports.useConditionalUpdateEffect = exports.useConditionalEffect = exports.useRafCallback = exports.useDebounceCallback = void 0; | ||
// Callback | ||
@@ -48,1 +48,4 @@ var useDebounceCallback_1 = require("./useDebounceCallback"); | ||
Object.defineProperty(exports, "useSessionStorageValue", { enumerable: true, get: function () { return useSessionStorageValue_1.useSessionStorageValue; } }); | ||
// Sensor | ||
var useResizeObserver_1 = require("./useResizeObserver"); | ||
Object.defineProperty(exports, "useResizeObserver", { enumerable: true, get: function () { return useResizeObserver_1.useResizeObserver; } }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.useResizeObserver = void 0; | ||
var react_1 = require("react"); | ||
var useSyncedRef_1 = require("./useSyncedRef"); | ||
var const_1 = require("./util/const"); | ||
var observerSingleton; | ||
function getResizeObserver() { | ||
if (!const_1.isBrowser) | ||
return undefined; | ||
if (observerSingleton) | ||
return observerSingleton; | ||
var callbacks = new Map(); | ||
var observer = new ResizeObserver(function (entries) { | ||
entries.forEach(function (entry) { var _a; return (_a = callbacks.get(entry.target)) === null || _a === void 0 ? void 0 : _a.forEach(function (cb) { return cb(entry); }); }); | ||
}); | ||
observerSingleton = { | ||
observer: observer, | ||
subscribe: function (target, callback) { | ||
var cbs = callbacks.get(target); | ||
if (!cbs) { | ||
// if target has no observers yet - register it | ||
cbs = new Set(); | ||
callbacks.set(target, cbs); | ||
observer.observe(target); | ||
} | ||
// as Set is duplicate-safe - simply add callback on each call | ||
cbs.add(callback); | ||
}, | ||
unsubscribe: function (target, callback) { | ||
var cbs = callbacks.get(target); | ||
// else branch should never occur in case of normal execution | ||
// because callbacks map is hidden in closure - it is impossible to | ||
// simulate situation with non-existent `cbs` Set | ||
/* istanbul ignore else */ | ||
if (cbs) { | ||
// remove current observer | ||
cbs.delete(callback); | ||
if (!cbs.size) { | ||
// if no observers left unregister target completely | ||
callbacks.delete(target); | ||
observer.unobserve(target); | ||
} | ||
} | ||
}, | ||
}; | ||
return observerSingleton; | ||
} | ||
/** | ||
* Invokes a callback whenever ResizeObserver detects a change to target's size. | ||
* | ||
* @param target React reference or Element to track. | ||
* @param callback Callback that will be invoked on resize. | ||
*/ | ||
function useResizeObserver(target, callback) { | ||
var ro = getResizeObserver(); | ||
var cb = useSyncedRef_1.useSyncedRef(callback); | ||
react_1.useEffect(function () { | ||
// quite difficult to cover with tests, but the 'if' branch is pretty | ||
// straightforward: do nothing, it is safe to exclude from LOC | ||
/* istanbul ignore if */ | ||
if (!ro) | ||
return; | ||
// as unsubscription in internals of our ResizeObserver abstraction can | ||
// happen a bit later than effect cleanup invocation - we need a marker, | ||
// that this handler should not be invoked anymore | ||
var subscribed = true; | ||
var tgt = target && 'current' in target ? target.current : target; | ||
if (!tgt) | ||
return; | ||
var handler = function () { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
// it is reinsurance for the highly asynchronous invocations, almost | ||
// impossible to achieve in tests, thus excluding from LOC | ||
/* istanbul ignore else */ | ||
if (subscribed) { | ||
cb.current.apply(cb, args); | ||
} | ||
}; | ||
ro.subscribe(tgt, handler); | ||
// eslint-disable-next-line consistent-return | ||
return function () { | ||
subscribed = false; | ||
ro.unsubscribe(tgt, handler); | ||
}; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [target, ro]); | ||
} | ||
exports.useResizeObserver = useResizeObserver; |
@@ -20,1 +20,2 @@ export { useDebounceCallback } from './useDebounceCallback'; | ||
export { useSessionStorageValue } from './useSessionStorageValue'; | ||
export { useResizeObserver, IUseResizeObserverCallback } from './useResizeObserver'; |
@@ -26,1 +26,3 @@ // Callback | ||
export { useSessionStorageValue } from "./useSessionStorageValue.js"; | ||
// Sensor | ||
export { useResizeObserver } from "./useResizeObserver.js"; |
@@ -1,1 +0,88 @@ | ||
"use strict"; | ||
import { useEffect } from 'react'; | ||
import { useSyncedRef } from "./useSyncedRef.js"; | ||
import { isBrowser } from "./util/const.js"; | ||
var observerSingleton; | ||
function getResizeObserver() { | ||
if (!isBrowser) | ||
return undefined; | ||
if (observerSingleton) | ||
return observerSingleton; | ||
var callbacks = new Map(); | ||
var observer = new ResizeObserver(function (entries) { | ||
entries.forEach(function (entry) { var _a; return (_a = callbacks.get(entry.target)) === null || _a === void 0 ? void 0 : _a.forEach(function (cb) { return cb(entry); }); }); | ||
}); | ||
observerSingleton = { | ||
observer: observer, | ||
subscribe: function (target, callback) { | ||
var cbs = callbacks.get(target); | ||
if (!cbs) { | ||
// if target has no observers yet - register it | ||
cbs = new Set(); | ||
callbacks.set(target, cbs); | ||
observer.observe(target); | ||
} | ||
// as Set is duplicate-safe - simply add callback on each call | ||
cbs.add(callback); | ||
}, | ||
unsubscribe: function (target, callback) { | ||
var cbs = callbacks.get(target); | ||
// else branch should never occur in case of normal execution | ||
// because callbacks map is hidden in closure - it is impossible to | ||
// simulate situation with non-existent `cbs` Set | ||
/* istanbul ignore else */ | ||
if (cbs) { | ||
// remove current observer | ||
cbs.delete(callback); | ||
if (!cbs.size) { | ||
// if no observers left unregister target completely | ||
callbacks.delete(target); | ||
observer.unobserve(target); | ||
} | ||
} | ||
}, | ||
}; | ||
return observerSingleton; | ||
} | ||
/** | ||
* Invokes a callback whenever ResizeObserver detects a change to target's size. | ||
* | ||
* @param target React reference or Element to track. | ||
* @param callback Callback that will be invoked on resize. | ||
*/ | ||
export function useResizeObserver(target, callback) { | ||
var ro = getResizeObserver(); | ||
var cb = useSyncedRef(callback); | ||
useEffect(function () { | ||
// quite difficult to cover with tests, but the 'if' branch is pretty | ||
// straightforward: do nothing, it is safe to exclude from LOC | ||
/* istanbul ignore if */ | ||
if (!ro) | ||
return; | ||
// as unsubscription in internals of our ResizeObserver abstraction can | ||
// happen a bit later than effect cleanup invocation - we need a marker, | ||
// that this handler should not be invoked anymore | ||
var subscribed = true; | ||
var tgt = target && 'current' in target ? target.current : target; | ||
if (!tgt) | ||
return; | ||
var handler = function () { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
// it is reinsurance for the highly asynchronous invocations, almost | ||
// impossible to achieve in tests, thus excluding from LOC | ||
/* istanbul ignore else */ | ||
if (subscribed) { | ||
cb.current.apply(cb, args); | ||
} | ||
}; | ||
ro.subscribe(tgt, handler); | ||
// eslint-disable-next-line consistent-return | ||
return function () { | ||
subscribed = false; | ||
ro.unsubscribe(tgt, handler); | ||
}; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [target, ro]); | ||
} |
@@ -20,1 +20,2 @@ export { useDebounceCallback } from './useDebounceCallback'; | ||
export { useSessionStorageValue } from './useSessionStorageValue'; | ||
export { useResizeObserver, IUseResizeObserverCallback } from './useResizeObserver'; |
@@ -26,1 +26,3 @@ // Callback | ||
export { useSessionStorageValue } from "./useSessionStorageValue.js"; | ||
// Sensor | ||
export { useResizeObserver } from "./useResizeObserver.js"; |
@@ -1,1 +0,84 @@ | ||
"use strict"; | ||
import { useEffect } from 'react'; | ||
import { useSyncedRef } from "./useSyncedRef.js"; | ||
import { isBrowser } from "./util/const.js"; | ||
let observerSingleton; | ||
function getResizeObserver() { | ||
if (!isBrowser) | ||
return undefined; | ||
if (observerSingleton) | ||
return observerSingleton; | ||
const callbacks = new Map(); | ||
const observer = new ResizeObserver((entries) => { | ||
entries.forEach((entry) => callbacks.get(entry.target)?.forEach((cb) => cb(entry))); | ||
}); | ||
observerSingleton = { | ||
observer, | ||
subscribe: (target, callback) => { | ||
let cbs = callbacks.get(target); | ||
if (!cbs) { | ||
// if target has no observers yet - register it | ||
cbs = new Set(); | ||
callbacks.set(target, cbs); | ||
observer.observe(target); | ||
} | ||
// as Set is duplicate-safe - simply add callback on each call | ||
cbs.add(callback); | ||
}, | ||
unsubscribe: (target, callback) => { | ||
const cbs = callbacks.get(target); | ||
// else branch should never occur in case of normal execution | ||
// because callbacks map is hidden in closure - it is impossible to | ||
// simulate situation with non-existent `cbs` Set | ||
/* istanbul ignore else */ | ||
if (cbs) { | ||
// remove current observer | ||
cbs.delete(callback); | ||
if (!cbs.size) { | ||
// if no observers left unregister target completely | ||
callbacks.delete(target); | ||
observer.unobserve(target); | ||
} | ||
} | ||
}, | ||
}; | ||
return observerSingleton; | ||
} | ||
/** | ||
* Invokes a callback whenever ResizeObserver detects a change to target's size. | ||
* | ||
* @param target React reference or Element to track. | ||
* @param callback Callback that will be invoked on resize. | ||
*/ | ||
export function useResizeObserver(target, callback) { | ||
const ro = getResizeObserver(); | ||
const cb = useSyncedRef(callback); | ||
useEffect(() => { | ||
// quite difficult to cover with tests, but the 'if' branch is pretty | ||
// straightforward: do nothing, it is safe to exclude from LOC | ||
/* istanbul ignore if */ | ||
if (!ro) | ||
return; | ||
// as unsubscription in internals of our ResizeObserver abstraction can | ||
// happen a bit later than effect cleanup invocation - we need a marker, | ||
// that this handler should not be invoked anymore | ||
let subscribed = true; | ||
const tgt = target && 'current' in target ? target.current : target; | ||
if (!tgt) | ||
return; | ||
const handler = (...args) => { | ||
// it is reinsurance for the highly asynchronous invocations, almost | ||
// impossible to achieve in tests, thus excluding from LOC | ||
/* istanbul ignore else */ | ||
if (subscribed) { | ||
cb.current(...args); | ||
} | ||
}; | ||
ro.subscribe(tgt, handler); | ||
// eslint-disable-next-line consistent-return | ||
return () => { | ||
subscribed = false; | ||
ro.unsubscribe(tgt, handler); | ||
}; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [target, ro]); | ||
} |
{ | ||
"name": "@react-hookz/web", | ||
"version": "1.20.4", | ||
"version": "1.21.0", | ||
"description": "React hooks done right, for browser and SSR.", | ||
@@ -94,3 +94,3 @@ "keywords": [ | ||
"@storybook/theming": "^6.2.9", | ||
"@testing-library/react-hooks": "^6.0.0", | ||
"@testing-library/react-hooks": "^7.0.0", | ||
"@types/jest": "^26.0.22", | ||
@@ -97,0 +97,0 @@ "@typescript-eslint/eslint-plugin": "^4.22.0", |
@@ -109,7 +109,12 @@ <div align="center"> | ||
- #### Side-effects | ||
- #### Side-effect | ||
- [**`useLocalStorageValue`**](https://react-hookz.github.io/?path=/docs/side-effects-uselocalstoragevalue) | ||
- [**`useLocalStorageValue`**](https://react-hookz.github.io/?path=/docs/side-effect-uselocalstoragevalue) | ||
— Manages a single LocalStorage key. | ||
- [**`useSessionStorageValue`**](https://react-hookz.github.io/?path=/docs/side-effects-usesessionstoragevalue) | ||
- [**`useSessionStorageValue`**](https://react-hookz.github.io/?path=/docs/side-effect-usesessionstoragevalue) | ||
— Manages a single SessionStorage key. | ||
- #### Sensor | ||
- [**`useResizeObserver`**](https://react-hookz.github.io/?path=/docs/sensor-useresizeobserver) | ||
— Invokes a callback whenever ResizeObserver detects a change to target's size. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
159979
3199
120