diff --git a/.eslintrc.js b/.eslintrc.js index c793d67d..3ce53a37 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -36,6 +36,12 @@ module.exports = { ], extends: ['@react-hookz/eslint-config/react', '@react-hookz/eslint-config/jest'], }, + { + files: ['**/__tests__/**/*.jsx', '**/__tests__/**/*.tsx'], + rules: { + 'jest/expect-expect': 'off', + }, + }, { files: ['**/__docs__/**', '**/__tests__/**'], rules: { diff --git a/README.md b/README.md index 6c098141..817303fb 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,8 @@ Coming from `react-use`? Check out our — Like `useSafeState` but its state setter is throttled. - [**`useValidator`**](https://react-hookz.github.io/web/?path=/docs/state-usevalidator--example) — Performs validation when any of the provided dependencies change. + - [**`useStateRef`**](https://react-hookz.github.io/web/?path=/docs/state-usestateref--example) + — Hook with callback which provide access to DOM node reference. - #### Navigator diff --git a/package.json b/package.json index fe48c0b7..58040508 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "@storybook/theming": "^6.5.16", "@swc/core": "^1.3.28", "@swc/jest": "^0.2.24", + "@testing-library/react": "12.1.4", "@testing-library/react-hooks": "^8.0.1", "@types/jest": "^29.4.0", "@types/js-cookie": "^3.0.2", diff --git a/src/index.ts b/src/index.ts index dc3b3f8f..5d342414 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,6 +40,7 @@ export * from './useSet'; export * from './useToggle'; export * from './useThrottledState'; export * from './useValidator'; +export * from './useStateRef'; // Navigator export * from './useNetworkState'; diff --git a/src/useStateRef/__docs__/example.stories.tsx b/src/useStateRef/__docs__/example.stories.tsx new file mode 100644 index 00000000..be3baa1e --- /dev/null +++ b/src/useStateRef/__docs__/example.stories.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { useStateRef } from '../..'; + +export const Example: React.FC = () => { + const [stateRef, setStateRef] = useStateRef((node) => ({ + height: node?.clientHeight ?? 0, + width: node?.clientWidth ?? 0, + })); + + return ( +
+
{JSON.stringify(stateRef, undefined, 2)}
+
+ ); +}; diff --git a/src/useStateRef/__docs__/story.mdx b/src/useStateRef/__docs__/story.mdx new file mode 100644 index 00000000..82c1a3c5 --- /dev/null +++ b/src/useStateRef/__docs__/story.mdx @@ -0,0 +1,36 @@ +import { Canvas, Meta, Story } from '@storybook/addon-docs'; +import { Example } from './example.stories'; +import { ImportPath } from '../../__docs__/ImportPath'; + + + +# useStateRef + +Hook with callback which provide access to DOM node reference. + +#### Example + + + + + +## Reference + +```ts +export function useStateRef( + refCallback: (node: Node) => StateRef +): readonly [StateRef | null, (node: Node) => void]; +``` + +#### Importing + + + +#### Arguments + +- **refCallback** _`(node: HTMLElement) => unknown`_ - Function which call on mount and unmount of component. + +#### Return + +- _**[0]**_ _`unknown`_ - return value of `refCallback` +- _**[1]**_ _`(node: HTMLElement) => void`_ - handler which update `stateRef` diff --git a/src/useStateRef/__tests__/dom.tsx b/src/useStateRef/__tests__/dom.tsx new file mode 100644 index 00000000..02b5a064 --- /dev/null +++ b/src/useStateRef/__tests__/dom.tsx @@ -0,0 +1,139 @@ +import { renderHook } from '@testing-library/react-hooks/dom'; +import { fireEvent, render } from '@testing-library/react'; +import React, { useReducer, useEffect } from 'react'; +import { useStateRef } from '../../index'; + +describe('useStateRef', () => { + it('should be defined', () => { + expect(useStateRef).toBeDefined(); + }); + + it('should render', () => { + const { result } = renderHook(() => useStateRef(() => null)); + expect(result.error).toBeUndefined(); + }); + + it('should resolve `refCallback`', () => { + const Component = () => { + const [stateRef, setStateRef] = useStateRef( + (node: HTMLDivElement | null) => node?.tagName.toLowerCase() ?? 'none' + ); + + return ( +
+

my parent is {stateRef}

+
+ ); + }; + + const { getByText } = render(); + + getByText('my parent is div'); + }); + + it('should call once', () => { + const spy = jest.fn(); + const Component = () => { + const [stateRef, setStateRef] = useStateRef((node: HTMLDivElement | null) => { + spy(); + + return node?.tagName.toLowerCase() ?? 'none'; + }); + const force = useReducer((state) => !state, false)[1]; + + return ( +
+
+

my parent is {stateRef}

+
+ +
+ ); + }; + + const { getByText } = render(); + + getByText('my parent is div'); + + fireEvent.click(getByText('force')); + fireEvent.click(getByText('force')); + fireEvent.click(getByText('force')); + + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('should call on unmount', () => { + const spy = jest.fn(); + + const Child = () => { + const [stateRef, setStateRef] = useStateRef((node: HTMLDivElement | null) => { + spy(); + + return node?.tagName.toLowerCase() ?? 'none'; + }); + + return ( +
+
+

my parent is {stateRef}

+
+
+ ); + }; + const Parent = () => { + const [displayChild, toggle] = useReducer((state) => !state, true); + + return ( + <> + {displayChild && } + + + ); + }; + + const { getByText } = render(); + + getByText('my parent is div'); + expect(spy).toHaveBeenCalledTimes(1); + + fireEvent.click(getByText('toggle component')); + + expect(spy).toHaveBeenCalledTimes(2); + }); + + it('should call before `useEffect`', () => { + const refCallbackSpy = jest.fn(); + const effectSpy = jest.fn(); + + const Component = () => { + const [stateRef, setStateRef] = useStateRef((node: HTMLDivElement | null) => { + refCallbackSpy(); + + return node?.tagName.toLowerCase() ?? 'none'; + }); + + useEffect(() => { + if (!refCallbackSpy.mock.calls.length) { + effectSpy(); + } + }); + + return ( +
+

my parent is {stateRef}

+
+ ); + }; + + const { getByText } = render(); + + getByText('my parent is div'); + + expect(refCallbackSpy).toHaveBeenCalledTimes(1); + expect(effectSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/src/useStateRef/__tests__/ssr.ts b/src/useStateRef/__tests__/ssr.ts new file mode 100644 index 00000000..fe402f73 --- /dev/null +++ b/src/useStateRef/__tests__/ssr.ts @@ -0,0 +1,13 @@ +import { renderHook } from '@testing-library/react-hooks/server'; +import { useStateRef } from '../..'; + +describe('useStateRef', () => { + it('should be defined', () => { + expect(useStateRef).toBeDefined(); + }); + + it('should render', () => { + const { result } = renderHook(() => useStateRef(() => null)); + expect(result.error).toBeUndefined(); + }); +}); diff --git a/src/useStateRef/index.ts b/src/useStateRef/index.ts new file mode 100644 index 00000000..914f2371 --- /dev/null +++ b/src/useStateRef/index.ts @@ -0,0 +1,25 @@ +import { useCallback, useState } from 'react'; + +import { useSyncedRef } from '../useSyncedRef'; + +/** + * Hook with callback which provide access to DOM node reference. + * + * @param refCallback Function which call on mount and unmount of component + * @returns return value of `refCallback` and handler + */ +export const useStateRef = ( + refCallback: (node: Node) => StateRef +): readonly [StateRef | null, (node: Node) => void] => { + const [stateRef, setStateRefImpl] = useState(null); + const syncedRefCallback = useSyncedRef(refCallback); + + const setStateRef = useCallback( + (...params: Parameters) => { + setStateRefImpl(syncedRefCallback.current(...params)); + }, + [syncedRefCallback] + ); + + return [stateRef, setStateRef] as const; +}; diff --git a/yarn.lock b/yarn.lock index e4b781ad..b6c8a418 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3586,6 +3586,20 @@ "@jest/create-cache-key-function" "^27.4.2" jsonc-parser "^3.2.0" +"@testing-library/dom@^8.0.0": + version "8.20.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.0.tgz#914aa862cef0f5e89b98cc48e3445c4c921010f6" + integrity sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "^5.0.0" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.4.4" + pretty-format "^27.0.2" + "@testing-library/react-hooks@^8.0.1": version "8.0.1" resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12" @@ -3594,6 +3608,15 @@ "@babel/runtime" "^7.12.5" react-error-boundary "^3.1.0" +"@testing-library/react@12.1.4": + version "12.1.4" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.4.tgz#09674b117e550af713db3f4ec4c0942aa8bbf2c0" + integrity sha512-jiPKOm7vyUw311Hn/HlNQ9P8/lHNtArAx0PisXyFixDDvfl8DbD6EUdbshK5eqauvBSvzZd19itqQ9j3nferJA== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^8.0.0" + "@types/react-dom" "*" + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -3626,6 +3649,11 @@ dependencies: "@types/estree" "*" +"@types/aria-query@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc" + integrity sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q== + "@types/babel__core@^7.1.14": version "7.1.20" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.20.tgz#e168cdd612c92a2d335029ed62ac94c95b362359" @@ -3880,7 +3908,7 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== -"@types/react-dom@^18.0.6": +"@types/react-dom@*", "@types/react-dom@^18.0.6": version "18.0.10" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.10.tgz#3b66dec56aa0f16a6cc26da9e9ca96c35c0b4352" integrity sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg== @@ -4691,6 +4719,13 @@ aria-query@^4.2.2: "@babel/runtime" "^7.10.2" "@babel/runtime-corejs3" "^7.10.2" +aria-query@^5.0.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -6592,6 +6627,29 @@ dedent@0.7.0, dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +deep-equal@^2.0.5: + version "2.2.0" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.0.tgz#5caeace9c781028b9ff459f33b779346637c43e6" + integrity sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw== + dependencies: + call-bind "^1.0.2" + es-get-iterator "^1.1.2" + get-intrinsic "^1.1.3" + is-arguments "^1.1.1" + is-array-buffer "^3.0.1" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -6812,6 +6870,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + dom-converter@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -7107,6 +7170,21 @@ es-get-iterator@^1.0.2: is-string "^1.0.5" isarray "^2.0.5" +es-get-iterator@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" @@ -9139,7 +9217,7 @@ is-alphanumerical@^2.0.0: is-alphabetical "^2.0.0" is-decimal "^2.0.0" -is-arguments@^1.1.0: +is-arguments@^1.1.0, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -9155,6 +9233,15 @@ is-array-buffer@^3.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.3" +is-array-buffer@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" + integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -9246,7 +9333,7 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -9370,7 +9457,7 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-map@^2.0.2: +is-map@^2.0.1, is-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== @@ -9459,7 +9546,7 @@ is-regex@^1.1.2, is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-set@^2.0.2: +is-set@^2.0.1, is-set@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== @@ -9545,6 +9632,11 @@ is-utf8@^0.2.0, is-utf8@^0.2.1: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -9552,6 +9644,14 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + is-whitespace-character@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" @@ -10890,6 +10990,11 @@ lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea" integrity sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA== +lz-string@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" + integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== + make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -12304,6 +12409,14 @@ object-inspect@^1.12.2, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -13200,6 +13313,15 @@ pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" +pretty-format@^27.0.2: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + pretty-format@^29.0.0, pretty-format@^29.4.0: version "29.4.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.0.tgz#766f071bb1c53f1ef8000c105bbeb649e86eb993" @@ -14761,6 +14883,13 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + store2@^2.12.0: version "2.14.2" resolved "https://registry.yarnpkg.com/store2/-/store2-2.14.2.tgz#56138d200f9fe5f582ad63bc2704dbc0e4a45068" @@ -16254,6 +16383,16 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"