@react-aria/utils 3.25.3 → 3.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/animation.main.js +97 -0
- package/dist/animation.main.js.map +1 -0
- package/dist/animation.mjs +91 -0
- package/dist/animation.module.js +91 -0
- package/dist/animation.module.js.map +1 -0
- package/dist/constants.main.js +25 -0
- package/dist/constants.main.js.map +1 -0
- package/dist/constants.mjs +18 -0
- package/dist/constants.module.js +18 -0
- package/dist/constants.module.js.map +1 -0
- package/dist/focusWithoutScrolling.main.js +1 -1
- package/dist/focusWithoutScrolling.main.js.map +1 -1
- package/dist/focusWithoutScrolling.mjs +1 -1
- package/dist/focusWithoutScrolling.module.js +1 -1
- package/dist/focusWithoutScrolling.module.js.map +1 -1
- package/dist/import.mjs +9 -1
- package/dist/isScrollable.main.js +1 -0
- package/dist/isScrollable.main.js.map +1 -1
- package/dist/isScrollable.mjs +1 -0
- package/dist/isScrollable.module.js +1 -0
- package/dist/isScrollable.module.js.map +1 -1
- package/dist/keyboard.main.js +26 -0
- package/dist/keyboard.main.js.map +1 -0
- package/dist/keyboard.mjs +21 -0
- package/dist/keyboard.module.js +21 -0
- package/dist/keyboard.module.js.map +1 -0
- package/dist/main.js +15 -0
- package/dist/main.js.map +1 -1
- package/dist/mergeProps.main.js.map +1 -1
- package/dist/mergeProps.module.js.map +1 -1
- package/dist/module.js +9 -1
- package/dist/module.js.map +1 -1
- package/dist/openLink.main.js.map +1 -1
- package/dist/openLink.module.js.map +1 -1
- package/dist/scrollIntoView.main.js +15 -9
- package/dist/scrollIntoView.main.js.map +1 -1
- package/dist/scrollIntoView.mjs +15 -9
- package/dist/scrollIntoView.module.js +15 -9
- package/dist/scrollIntoView.module.js.map +1 -1
- package/dist/types.d.ts +35 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/useDescription.main.js.map +1 -1
- package/dist/useDescription.module.js.map +1 -1
- package/dist/useFormReset.main.js.map +1 -1
- package/dist/useFormReset.module.js.map +1 -1
- package/dist/useGlobalListeners.main.js +1 -2
- package/dist/useGlobalListeners.main.js.map +1 -1
- package/dist/useGlobalListeners.mjs +1 -2
- package/dist/useGlobalListeners.module.js +1 -2
- package/dist/useGlobalListeners.module.js.map +1 -1
- package/dist/useLoadMore.main.js.map +1 -1
- package/dist/useLoadMore.module.js.map +1 -1
- package/dist/useUpdateLayoutEffect.main.js +40 -0
- package/dist/useUpdateLayoutEffect.main.js.map +1 -0
- package/dist/useUpdateLayoutEffect.mjs +35 -0
- package/dist/useUpdateLayoutEffect.module.js +35 -0
- package/dist/useUpdateLayoutEffect.module.js.map +1 -0
- package/dist/useViewportSize.main.js +0 -1
- package/dist/useViewportSize.main.js.map +1 -1
- package/dist/useViewportSize.mjs +0 -1
- package/dist/useViewportSize.module.js +0 -1
- package/dist/useViewportSize.module.js.map +1 -1
- package/package.json +9 -7
- package/src/animation.ts +103 -0
- package/src/constants.ts +16 -0
- package/src/focusWithoutScrolling.ts +1 -1
- package/src/index.ts +4 -0
- package/src/isScrollable.ts +4 -1
- package/src/keyboard.tsx +27 -0
- package/src/mergeProps.ts +1 -1
- package/src/openLink.tsx +1 -1
- package/src/scrollIntoView.ts +31 -15
- package/src/useFormReset.ts +1 -1
- package/src/useGlobalListeners.ts +2 -2
- package/src/useLoadMore.ts +1 -1
- package/src/useUpdateLayoutEffect.ts +37 -0
- package/src/useViewportSize.ts +0 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {useLayoutEffect as $f0a04ccd8dbdd83b$export$e5c5a5f917a5871c} from "./useLayoutEffect.module.js";
|
|
2
|
+
import {useRef as $azsE2$useRef} from "react";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
6
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
8
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
11
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
12
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
13
|
+
* governing permissions and limitations under the License.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
function $ca9b37712f007381$export$72ef708ab07251f1(effect, dependencies) {
|
|
17
|
+
const isInitialMount = (0, $azsE2$useRef)(true);
|
|
18
|
+
const lastDeps = (0, $azsE2$useRef)(null);
|
|
19
|
+
(0, $f0a04ccd8dbdd83b$export$e5c5a5f917a5871c)(()=>{
|
|
20
|
+
isInitialMount.current = true;
|
|
21
|
+
return ()=>{
|
|
22
|
+
isInitialMount.current = false;
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
(0, $f0a04ccd8dbdd83b$export$e5c5a5f917a5871c)(()=>{
|
|
26
|
+
if (isInitialMount.current) isInitialMount.current = false;
|
|
27
|
+
else if (!lastDeps.current || dependencies.some((dep, i)=>!Object.is(dep, lastDeps[i]))) effect();
|
|
28
|
+
lastDeps.current = dependencies;
|
|
29
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
30
|
+
}, dependencies);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export {$ca9b37712f007381$export$72ef708ab07251f1 as useUpdateLayoutEffect};
|
|
35
|
+
//# sourceMappingURL=useUpdateLayoutEffect.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAMM,SAAS,0CAAsB,MAAsB,EAAE,YAAmB;IAC/E,MAAM,iBAAiB,CAAA,GAAA,aAAK,EAAE;IAC9B,MAAM,WAAW,CAAA,GAAA,aAAK,EAAgB;IAEtC,CAAA,GAAA,yCAAc,EAAE;QACd,eAAe,OAAO,GAAG;QACzB,OAAO;YACL,eAAe,OAAO,GAAG;QAC3B;IACF,GAAG,EAAE;IAEL,CAAA,GAAA,yCAAc,EAAE;QACd,IAAI,eAAe,OAAO,EACxB,eAAe,OAAO,GAAG;aACpB,IAAI,CAAC,SAAS,OAAO,IAAI,aAAa,IAAI,CAAC,CAAC,KAAK,IAAM,CAAC,OAAO,EAAE,CAAC,KAAK,QAAQ,CAAC,EAAE,IACvF;QAEF,SAAS,OAAO,GAAG;IACnB,uDAAuD;IACzD,GAAG;AACL","sources":["packages/@react-aria/utils/src/useUpdateLayoutEffect.ts"],"sourcesContent":["/*\n * Copyright 2024 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {EffectCallback, useRef} from 'react';\nimport {useLayoutEffect} from './useLayoutEffect';\n\n// Like useLayoutEffect, but only called for updates after the initial render.\nexport function useUpdateLayoutEffect(effect: EffectCallback, dependencies: any[]) {\n const isInitialMount = useRef(true);\n const lastDeps = useRef<any[] | null>(null);\n\n useLayoutEffect(() => {\n isInitialMount.current = true;\n return () => {\n isInitialMount.current = false;\n };\n }, []);\n\n useLayoutEffect(() => {\n if (isInitialMount.current) {\n isInitialMount.current = false;\n } else if (!lastDeps.current || dependencies.some((dep, i) => !Object.is(dep, lastDeps[i]))) {\n effect();\n }\n lastDeps.current = dependencies;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, dependencies);\n}\n"],"names":[],"version":3,"file":"useUpdateLayoutEffect.module.js.map"}
|
|
@@ -19,7 +19,6 @@ $parcel$export(module.exports, "useViewportSize", () => $8b24bab62f5c65ad$export
|
|
|
19
19
|
* governing permissions and limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
// @ts-ignore
|
|
23
22
|
let $8b24bab62f5c65ad$var$visualViewport = typeof document !== 'undefined' && window.visualViewport;
|
|
24
23
|
function $8b24bab62f5c65ad$export$d699905dd57c73ca() {
|
|
25
24
|
let isSSR = (0, $4gIVO$reactariassr.useIsSSR)();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;AAUD,
|
|
1
|
+
{"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;AAUD,IAAI,uCAAiB,OAAO,aAAa,eAAe,OAAO,cAAc;AAEtE,SAAS;IACd,IAAI,QAAQ,CAAA,GAAA,4BAAO;IACnB,IAAI,CAAC,MAAM,QAAQ,GAAG,CAAA,GAAA,qBAAO,EAAE,IAAM,QAAQ;YAAC,OAAO;YAAG,QAAQ;QAAC,IAAI;IAErE,CAAA,GAAA,sBAAQ,EAAE;QACR,wFAAwF;QACxF,IAAI,WAAW;YACb,QAAQ,CAAA;gBACN,IAAI,UAAU;gBACd,IAAI,QAAQ,KAAK,KAAK,KAAK,KAAK,IAAI,QAAQ,MAAM,KAAK,KAAK,MAAM,EAChE,OAAO;gBAET,OAAO;YACT;QACF;QAEA,IAAI,CAAC,sCACH,OAAO,gBAAgB,CAAC,UAAU;aAElC,qCAAe,gBAAgB,CAAC,UAAU;QAG5C,OAAO;YACL,IAAI,CAAC,sCACH,OAAO,mBAAmB,CAAC,UAAU;iBAErC,qCAAe,mBAAmB,CAAC,UAAU;QAEjD;IACF,GAAG,EAAE;IAEL,OAAO;AACT;AAEA,SAAS;IACP,OAAO;QACL,OAAO,AAAC,yCAAkB,iDAAA,2DAAA,qCAAgB,KAAK,KAAK,OAAO,UAAU;QACrE,QAAQ,AAAC,yCAAkB,iDAAA,2DAAA,qCAAgB,MAAM,KAAK,OAAO,WAAW;IAC1E;AACF","sources":["packages/@react-aria/utils/src/useViewportSize.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {useEffect, useState} from 'react';\nimport {useIsSSR} from '@react-aria/ssr';\n\ninterface ViewportSize {\n width: number,\n height: number\n}\n\nlet visualViewport = typeof document !== 'undefined' && window.visualViewport;\n\nexport function useViewportSize(): ViewportSize {\n let isSSR = useIsSSR();\n let [size, setSize] = useState(() => isSSR ? {width: 0, height: 0} : getViewportSize());\n\n useEffect(() => {\n // Use visualViewport api to track available height even on iOS virtual keyboard opening\n let onResize = () => {\n setSize(size => {\n let newSize = getViewportSize();\n if (newSize.width === size.width && newSize.height === size.height) {\n return size;\n }\n return newSize;\n });\n };\n\n if (!visualViewport) {\n window.addEventListener('resize', onResize);\n } else {\n visualViewport.addEventListener('resize', onResize);\n }\n\n return () => {\n if (!visualViewport) {\n window.removeEventListener('resize', onResize);\n } else {\n visualViewport.removeEventListener('resize', onResize);\n }\n };\n }, []);\n\n return size;\n}\n\nfunction getViewportSize(): ViewportSize {\n return {\n width: (visualViewport && visualViewport?.width) || window.innerWidth,\n height: (visualViewport && visualViewport?.height) || window.innerHeight\n };\n}\n"],"names":[],"version":3,"file":"useViewportSize.main.js.map"}
|
package/dist/useViewportSize.mjs
CHANGED
|
@@ -13,7 +13,6 @@ import {useIsSSR as $fuDHA$useIsSSR} from "@react-aria/ssr";
|
|
|
13
13
|
* governing permissions and limitations under the License.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
// @ts-ignore
|
|
17
16
|
let $5df64b3807dc15ee$var$visualViewport = typeof document !== 'undefined' && window.visualViewport;
|
|
18
17
|
function $5df64b3807dc15ee$export$d699905dd57c73ca() {
|
|
19
18
|
let isSSR = (0, $fuDHA$useIsSSR)();
|
|
@@ -13,7 +13,6 @@ import {useIsSSR as $fuDHA$useIsSSR} from "@react-aria/ssr";
|
|
|
13
13
|
* governing permissions and limitations under the License.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
// @ts-ignore
|
|
17
16
|
let $5df64b3807dc15ee$var$visualViewport = typeof document !== 'undefined' && window.visualViewport;
|
|
18
17
|
function $5df64b3807dc15ee$export$d699905dd57c73ca() {
|
|
19
18
|
let isSSR = (0, $fuDHA$useIsSSR)();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAUD,
|
|
1
|
+
{"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAUD,IAAI,uCAAiB,OAAO,aAAa,eAAe,OAAO,cAAc;AAEtE,SAAS;IACd,IAAI,QAAQ,CAAA,GAAA,eAAO;IACnB,IAAI,CAAC,MAAM,QAAQ,GAAG,CAAA,GAAA,eAAO,EAAE,IAAM,QAAQ;YAAC,OAAO;YAAG,QAAQ;QAAC,IAAI;IAErE,CAAA,GAAA,gBAAQ,EAAE;QACR,wFAAwF;QACxF,IAAI,WAAW;YACb,QAAQ,CAAA;gBACN,IAAI,UAAU;gBACd,IAAI,QAAQ,KAAK,KAAK,KAAK,KAAK,IAAI,QAAQ,MAAM,KAAK,KAAK,MAAM,EAChE,OAAO;gBAET,OAAO;YACT;QACF;QAEA,IAAI,CAAC,sCACH,OAAO,gBAAgB,CAAC,UAAU;aAElC,qCAAe,gBAAgB,CAAC,UAAU;QAG5C,OAAO;YACL,IAAI,CAAC,sCACH,OAAO,mBAAmB,CAAC,UAAU;iBAErC,qCAAe,mBAAmB,CAAC,UAAU;QAEjD;IACF,GAAG,EAAE;IAEL,OAAO;AACT;AAEA,SAAS;IACP,OAAO;QACL,OAAO,AAAC,yCAAkB,iDAAA,2DAAA,qCAAgB,KAAK,KAAK,OAAO,UAAU;QACrE,QAAQ,AAAC,yCAAkB,iDAAA,2DAAA,qCAAgB,MAAM,KAAK,OAAO,WAAW;IAC1E;AACF","sources":["packages/@react-aria/utils/src/useViewportSize.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {useEffect, useState} from 'react';\nimport {useIsSSR} from '@react-aria/ssr';\n\ninterface ViewportSize {\n width: number,\n height: number\n}\n\nlet visualViewport = typeof document !== 'undefined' && window.visualViewport;\n\nexport function useViewportSize(): ViewportSize {\n let isSSR = useIsSSR();\n let [size, setSize] = useState(() => isSSR ? {width: 0, height: 0} : getViewportSize());\n\n useEffect(() => {\n // Use visualViewport api to track available height even on iOS virtual keyboard opening\n let onResize = () => {\n setSize(size => {\n let newSize = getViewportSize();\n if (newSize.width === size.width && newSize.height === size.height) {\n return size;\n }\n return newSize;\n });\n };\n\n if (!visualViewport) {\n window.addEventListener('resize', onResize);\n } else {\n visualViewport.addEventListener('resize', onResize);\n }\n\n return () => {\n if (!visualViewport) {\n window.removeEventListener('resize', onResize);\n } else {\n visualViewport.removeEventListener('resize', onResize);\n }\n };\n }, []);\n\n return size;\n}\n\nfunction getViewportSize(): ViewportSize {\n return {\n width: (visualViewport && visualViewport?.width) || window.innerWidth,\n height: (visualViewport && visualViewport?.height) || window.innerHeight\n };\n}\n"],"names":[],"version":3,"file":"useViewportSize.module.js.map"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/utils",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.27.0",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -22,16 +22,18 @@
|
|
|
22
22
|
"url": "https://github.com/adobe/react-spectrum"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@react-aria/ssr": "^3.9.
|
|
26
|
-
"@react-stately/utils": "^3.10.
|
|
27
|
-
"@react-types/shared": "^3.
|
|
25
|
+
"@react-aria/ssr": "^3.9.7",
|
|
26
|
+
"@react-stately/utils": "^3.10.5",
|
|
27
|
+
"@react-types/shared": "^3.27.0",
|
|
28
28
|
"@swc/helpers": "^0.5.0",
|
|
29
29
|
"clsx": "^2.0.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0"
|
|
32
|
+
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1",
|
|
33
|
+
"react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
|
|
33
34
|
},
|
|
34
35
|
"publishConfig": {
|
|
35
36
|
"access": "public"
|
|
36
|
-
}
|
|
37
|
-
|
|
37
|
+
},
|
|
38
|
+
"gitHead": "09e7f44bebdc9d89122926b2b439a0a38a2814ea"
|
|
39
|
+
}
|
package/src/animation.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {flushSync} from 'react-dom';
|
|
14
|
+
import {RefObject, useCallback, useState} from 'react';
|
|
15
|
+
import {useLayoutEffect} from './useLayoutEffect';
|
|
16
|
+
|
|
17
|
+
export function useEnterAnimation(ref: RefObject<HTMLElement | null>, isReady: boolean = true) {
|
|
18
|
+
let [isEntering, setEntering] = useState(true);
|
|
19
|
+
let isAnimationReady = isEntering && isReady;
|
|
20
|
+
|
|
21
|
+
// There are two cases for entry animations:
|
|
22
|
+
// 1. CSS @keyframes. The `animation` property is set during the isEntering state, and it is removed after the animation finishes.
|
|
23
|
+
// 2. CSS transitions. The initial styles are applied during the isEntering state, and removed immediately, causing the transition to occur.
|
|
24
|
+
//
|
|
25
|
+
// In the second case, cancel any transitions that were triggered prior to the isEntering = false state (when the transition is supposed to start).
|
|
26
|
+
// This can happen when isReady starts as false (e.g. popovers prior to placement calculation).
|
|
27
|
+
useLayoutEffect(() => {
|
|
28
|
+
if (isAnimationReady && ref.current && 'getAnimations' in ref.current) {
|
|
29
|
+
for (let animation of ref.current.getAnimations()) {
|
|
30
|
+
if (animation instanceof CSSTransition) {
|
|
31
|
+
animation.cancel();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}, [ref, isAnimationReady]);
|
|
36
|
+
|
|
37
|
+
useAnimation(ref, isAnimationReady, useCallback(() => setEntering(false), []));
|
|
38
|
+
return isAnimationReady;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useExitAnimation(ref: RefObject<HTMLElement | null>, isOpen: boolean) {
|
|
42
|
+
let [exitState, setExitState] = useState<'closed' | 'open' | 'exiting'>(isOpen ? 'open' : 'closed');
|
|
43
|
+
|
|
44
|
+
switch (exitState) {
|
|
45
|
+
case 'open':
|
|
46
|
+
// If isOpen becomes false, set the state to exiting.
|
|
47
|
+
if (!isOpen) {
|
|
48
|
+
setExitState('exiting');
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
case 'closed':
|
|
52
|
+
case 'exiting':
|
|
53
|
+
// If we are exiting and isOpen becomes true, the animation was interrupted.
|
|
54
|
+
// Reset the state to open.
|
|
55
|
+
if (isOpen) {
|
|
56
|
+
setExitState('open');
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let isExiting = exitState === 'exiting';
|
|
62
|
+
useAnimation(
|
|
63
|
+
ref,
|
|
64
|
+
isExiting,
|
|
65
|
+
useCallback(() => {
|
|
66
|
+
// Set the state to closed, which will cause the element to be unmounted.
|
|
67
|
+
setExitState(state => state === 'exiting' ? 'closed' : state);
|
|
68
|
+
}, [])
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return isExiting;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function useAnimation(ref: RefObject<HTMLElement | null>, isActive: boolean, onEnd: () => void) {
|
|
75
|
+
useLayoutEffect(() => {
|
|
76
|
+
if (isActive && ref.current) {
|
|
77
|
+
if (!('getAnimations' in ref.current)) {
|
|
78
|
+
// JSDOM
|
|
79
|
+
onEnd();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let animations = ref.current.getAnimations();
|
|
84
|
+
if (animations.length === 0) {
|
|
85
|
+
onEnd();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let canceled = false;
|
|
90
|
+
Promise.all(animations.map(a => a.finished)).then(() => {
|
|
91
|
+
if (!canceled) {
|
|
92
|
+
flushSync(() => {
|
|
93
|
+
onEnd();
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}).catch(() => {});
|
|
97
|
+
|
|
98
|
+
return () => {
|
|
99
|
+
canceled = true;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}, [ref, isActive, onEnd]);
|
|
103
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// Custom event names for updating the autocomplete's aria-activedecendant.
|
|
14
|
+
export const CLEAR_FOCUS_EVENT = 'react-aria-clear-focus';
|
|
15
|
+
export const FOCUS_EVENT = 'react-aria-focus';
|
|
16
|
+
export const UPDATE_ACTIVEDESCENDANT = 'react-aria-update-activedescendant';
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ export {useGlobalListeners} from './useGlobalListeners';
|
|
|
24
24
|
export {useLabels} from './useLabels';
|
|
25
25
|
export {useObjectRef} from './useObjectRef';
|
|
26
26
|
export {useUpdateEffect} from './useUpdateEffect';
|
|
27
|
+
export {useUpdateLayoutEffect} from './useUpdateLayoutEffect';
|
|
27
28
|
export {useLayoutEffect} from './useLayoutEffect';
|
|
28
29
|
export {useResizeObserver} from './useResizeObserver';
|
|
29
30
|
export {useSyncRef} from './useSyncRef';
|
|
@@ -42,3 +43,6 @@ export {useEffectEvent} from './useEffectEvent';
|
|
|
42
43
|
export {useDeepMemo} from './useDeepMemo';
|
|
43
44
|
export {useFormReset} from './useFormReset';
|
|
44
45
|
export {useLoadMore} from './useLoadMore';
|
|
46
|
+
export {CLEAR_FOCUS_EVENT, FOCUS_EVENT, UPDATE_ACTIVEDESCENDANT} from './constants';
|
|
47
|
+
export {isCtrlKeyPressed} from './keyboard';
|
|
48
|
+
export {useEnterAnimation, useExitAnimation} from './animation';
|
package/src/isScrollable.ts
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
export function isScrollable(node: Element, checkForOverflow?: boolean): boolean {
|
|
13
|
+
export function isScrollable(node: Element | null, checkForOverflow?: boolean): boolean {
|
|
14
|
+
if (!node) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
14
17
|
let style = window.getComputedStyle(node);
|
|
15
18
|
let isScrollable = /(auto|scroll)/.test(style.overflow + style.overflowX + style.overflowY);
|
|
16
19
|
|
package/src/keyboard.tsx
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {isMac} from './platform';
|
|
14
|
+
|
|
15
|
+
interface Event {
|
|
16
|
+
altKey: boolean,
|
|
17
|
+
ctrlKey: boolean,
|
|
18
|
+
metaKey: boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isCtrlKeyPressed(e: Event) {
|
|
22
|
+
if (isMac()) {
|
|
23
|
+
return e.metaKey;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return e.ctrlKey;
|
|
27
|
+
}
|
package/src/mergeProps.ts
CHANGED
|
@@ -23,7 +23,7 @@ type PropsArg = Props | null | undefined;
|
|
|
23
23
|
// taken from: https://stackoverflow.com/questions/51603250/typescript-3-parameter-list-intersection-type/51604379#51604379
|
|
24
24
|
type TupleTypes<T> = { [P in keyof T]: T[P] } extends { [key: number]: infer V } ? NullToObject<V> : never;
|
|
25
25
|
type NullToObject<T> = T extends (null | undefined) ? {} : T;
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
|
28
28
|
|
|
29
29
|
/**
|
package/src/openLink.tsx
CHANGED
|
@@ -171,7 +171,7 @@ export function getSyntheticLinkProps(props: LinkDOMProps) {
|
|
|
171
171
|
};
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
export function useLinkProps(props
|
|
174
|
+
export function useLinkProps(props?: LinkDOMProps) {
|
|
175
175
|
let router = useRouter();
|
|
176
176
|
const href = router.useHref(props?.href ?? '');
|
|
177
177
|
return {
|
package/src/scrollIntoView.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {getScrollParents} from './getScrollParents';
|
|
|
14
14
|
|
|
15
15
|
interface ScrollIntoViewportOpts {
|
|
16
16
|
/** The optional containing element of the target to be centered in the viewport. */
|
|
17
|
-
containingElement?: Element
|
|
17
|
+
containingElement?: Element | null
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -30,24 +30,40 @@ export function scrollIntoView(scrollView: HTMLElement, element: HTMLElement) {
|
|
|
30
30
|
let x = scrollView.scrollLeft;
|
|
31
31
|
let y = scrollView.scrollTop;
|
|
32
32
|
|
|
33
|
-
// Account for top/left border offsetting the scroll top/Left
|
|
34
|
-
let {
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// Account for top/left border offsetting the scroll top/Left + scroll padding
|
|
34
|
+
let {
|
|
35
|
+
borderTopWidth,
|
|
36
|
+
borderLeftWidth,
|
|
37
|
+
scrollPaddingTop,
|
|
38
|
+
scrollPaddingRight,
|
|
39
|
+
scrollPaddingBottom,
|
|
40
|
+
scrollPaddingLeft
|
|
41
|
+
} = getComputedStyle(scrollView);
|
|
42
|
+
|
|
43
|
+
let borderAdjustedX = x + parseInt(borderLeftWidth, 10);
|
|
44
|
+
let borderAdjustedY = y + parseInt(borderTopWidth, 10);
|
|
37
45
|
// Ignore end/bottom border via clientHeight/Width instead of offsetHeight/Width
|
|
38
46
|
let maxX = borderAdjustedX + scrollView.clientWidth;
|
|
39
47
|
let maxY = borderAdjustedY + scrollView.clientHeight;
|
|
40
48
|
|
|
41
|
-
if
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
// Get scroll padding values as pixels - defaults to 0 if no scroll padding
|
|
50
|
+
// is used.
|
|
51
|
+
let scrollPaddingTopNumber = parseInt(scrollPaddingTop, 10) || 0;
|
|
52
|
+
let scrollPaddingBottomNumber = parseInt(scrollPaddingBottom, 10) || 0;
|
|
53
|
+
let scrollPaddingRightNumber = parseInt(scrollPaddingRight, 10) || 0;
|
|
54
|
+
let scrollPaddingLeftNumber = parseInt(scrollPaddingLeft, 10) || 0;
|
|
55
|
+
|
|
56
|
+
if (offsetX <= x + scrollPaddingLeftNumber) {
|
|
57
|
+
x = offsetX - parseInt(borderLeftWidth, 10) - scrollPaddingLeftNumber;
|
|
58
|
+
} else if (offsetX + width > maxX - scrollPaddingRightNumber) {
|
|
59
|
+
x += offsetX + width - maxX + scrollPaddingRightNumber;
|
|
45
60
|
}
|
|
46
|
-
if (offsetY <= borderAdjustedY) {
|
|
47
|
-
y = offsetY - parseInt(borderTopWidth, 10);
|
|
48
|
-
} else if (offsetY + height > maxY) {
|
|
49
|
-
y += offsetY + height - maxY;
|
|
61
|
+
if (offsetY <= borderAdjustedY + scrollPaddingTopNumber) {
|
|
62
|
+
y = offsetY - parseInt(borderTopWidth, 10) - scrollPaddingTopNumber;
|
|
63
|
+
} else if (offsetY + height > maxY - scrollPaddingBottomNumber) {
|
|
64
|
+
y += offsetY + height - maxY + scrollPaddingBottomNumber;
|
|
50
65
|
}
|
|
66
|
+
|
|
51
67
|
scrollView.scrollLeft = x;
|
|
52
68
|
scrollView.scrollTop = y;
|
|
53
69
|
}
|
|
@@ -81,8 +97,8 @@ function relativeOffset(ancestor: HTMLElement, child: HTMLElement, axis: 'left'|
|
|
|
81
97
|
* that will be centered in the viewport prior to scrolling the targetElement into view. If scrolling is prevented on
|
|
82
98
|
* the body (e.g. targetElement is in a popover), this will only scroll the scroll parents of the targetElement up to but not including the body itself.
|
|
83
99
|
*/
|
|
84
|
-
export function scrollIntoViewport(targetElement: Element, opts?: ScrollIntoViewportOpts) {
|
|
85
|
-
if (document.contains(targetElement)) {
|
|
100
|
+
export function scrollIntoViewport(targetElement: Element | null, opts?: ScrollIntoViewportOpts) {
|
|
101
|
+
if (targetElement && document.contains(targetElement)) {
|
|
86
102
|
let root = document.scrollingElement || document.documentElement;
|
|
87
103
|
let isScrollPrevented = window.getComputedStyle(root).overflow === 'hidden';
|
|
88
104
|
// If scrolling is not currently prevented then we aren’t in a overlay nor is a overlay open, just use element.scrollIntoView to bring the element into view
|
package/src/useFormReset.ts
CHANGED
|
@@ -15,7 +15,7 @@ import {useEffect, useRef} from 'react';
|
|
|
15
15
|
import {useEffectEvent} from './useEffectEvent';
|
|
16
16
|
|
|
17
17
|
export function useFormReset<T>(
|
|
18
|
-
ref: RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null
|
|
18
|
+
ref: RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null> | undefined,
|
|
19
19
|
initialValue: T,
|
|
20
20
|
onReset: (value: T) => void
|
|
21
21
|
) {
|
|
@@ -29,7 +29,7 @@ export function useGlobalListeners(): GlobalListeners {
|
|
|
29
29
|
listener(...args);
|
|
30
30
|
} : listener;
|
|
31
31
|
globalListeners.current.set(listener, {type, eventTarget, fn, options});
|
|
32
|
-
eventTarget.addEventListener(type,
|
|
32
|
+
eventTarget.addEventListener(type, fn, options);
|
|
33
33
|
}, []);
|
|
34
34
|
let removeGlobalListener = useCallback((eventTarget, type, listener, options) => {
|
|
35
35
|
let fn = globalListeners.current.get(listener)?.fn || listener;
|
|
@@ -42,7 +42,7 @@ export function useGlobalListeners(): GlobalListeners {
|
|
|
42
42
|
});
|
|
43
43
|
}, [removeGlobalListener]);
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
useEffect(() => {
|
|
47
47
|
return removeAllGlobalListeners;
|
|
48
48
|
}, [removeAllGlobalListeners]);
|
package/src/useLoadMore.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {EffectCallback, useRef} from 'react';
|
|
14
|
+
import {useLayoutEffect} from './useLayoutEffect';
|
|
15
|
+
|
|
16
|
+
// Like useLayoutEffect, but only called for updates after the initial render.
|
|
17
|
+
export function useUpdateLayoutEffect(effect: EffectCallback, dependencies: any[]) {
|
|
18
|
+
const isInitialMount = useRef(true);
|
|
19
|
+
const lastDeps = useRef<any[] | null>(null);
|
|
20
|
+
|
|
21
|
+
useLayoutEffect(() => {
|
|
22
|
+
isInitialMount.current = true;
|
|
23
|
+
return () => {
|
|
24
|
+
isInitialMount.current = false;
|
|
25
|
+
};
|
|
26
|
+
}, []);
|
|
27
|
+
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
if (isInitialMount.current) {
|
|
30
|
+
isInitialMount.current = false;
|
|
31
|
+
} else if (!lastDeps.current || dependencies.some((dep, i) => !Object.is(dep, lastDeps[i]))) {
|
|
32
|
+
effect();
|
|
33
|
+
}
|
|
34
|
+
lastDeps.current = dependencies;
|
|
35
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
36
|
+
}, dependencies);
|
|
37
|
+
}
|