@react-aria/utils 3.29.0 → 3.30.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.
Files changed (60) hide show
  1. package/dist/filterDOMProps.main.js +45 -2
  2. package/dist/filterDOMProps.main.js.map +1 -1
  3. package/dist/filterDOMProps.mjs +45 -2
  4. package/dist/filterDOMProps.module.js +45 -2
  5. package/dist/filterDOMProps.module.js.map +1 -1
  6. package/dist/import.mjs +3 -3
  7. package/dist/isElementVisible.main.js +43 -0
  8. package/dist/isElementVisible.main.js.map +1 -0
  9. package/dist/isElementVisible.mjs +38 -0
  10. package/dist/isElementVisible.module.js +38 -0
  11. package/dist/isElementVisible.module.js.map +1 -0
  12. package/dist/isFocusable.main.js +25 -3
  13. package/dist/isFocusable.main.js.map +1 -1
  14. package/dist/isFocusable.mjs +25 -3
  15. package/dist/isFocusable.module.js +25 -3
  16. package/dist/isFocusable.module.js.map +1 -1
  17. package/dist/main.js +2 -1
  18. package/dist/main.js.map +1 -1
  19. package/dist/module.js +3 -3
  20. package/dist/module.js.map +1 -1
  21. package/dist/openLink.main.js +9 -0
  22. package/dist/openLink.main.js.map +1 -1
  23. package/dist/openLink.mjs +9 -1
  24. package/dist/openLink.module.js +9 -1
  25. package/dist/openLink.module.js.map +1 -1
  26. package/dist/platform.main.js +2 -1
  27. package/dist/platform.main.js.map +1 -1
  28. package/dist/platform.mjs +2 -1
  29. package/dist/platform.module.js +2 -1
  30. package/dist/platform.module.js.map +1 -1
  31. package/dist/types.d.ts +10 -5
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/useEffectEvent.main.js +9 -1
  34. package/dist/useEffectEvent.main.js.map +1 -1
  35. package/dist/useEffectEvent.mjs +6 -2
  36. package/dist/useEffectEvent.module.js +6 -2
  37. package/dist/useEffectEvent.module.js.map +1 -1
  38. package/dist/useFormReset.main.js +1 -2
  39. package/dist/useFormReset.main.js.map +1 -1
  40. package/dist/useFormReset.mjs +2 -3
  41. package/dist/useFormReset.module.js +2 -3
  42. package/dist/useFormReset.module.js.map +1 -1
  43. package/dist/useLayoutEffect.main.js.map +1 -1
  44. package/dist/useLayoutEffect.module.js.map +1 -1
  45. package/dist/useLoadMoreSentinel.main.js +2 -2
  46. package/dist/useLoadMoreSentinel.main.js.map +1 -1
  47. package/dist/useLoadMoreSentinel.mjs +2 -2
  48. package/dist/useLoadMoreSentinel.module.js +2 -2
  49. package/dist/useLoadMoreSentinel.module.js.map +1 -1
  50. package/package.json +11 -7
  51. package/src/filterDOMProps.ts +54 -3
  52. package/src/index.ts +2 -2
  53. package/src/isElementVisible.ts +75 -0
  54. package/src/isFocusable.ts +31 -3
  55. package/src/openLink.tsx +17 -1
  56. package/src/platform.ts +13 -14
  57. package/src/useEffectEvent.ts +6 -2
  58. package/src/useFormReset.ts +3 -3
  59. package/src/useLayoutEffect.ts +1 -1
  60. package/src/useLoadMoreSentinel.ts +3 -3
@@ -20,9 +20,8 @@ $parcel$export(module.exports, "useFormReset", () => $1f205e845604a423$export$5a
20
20
  */
21
21
 
22
22
  function $1f205e845604a423$export$5add1d006293d136(ref, initialValue, onReset) {
23
- let resetValue = (0, $81vbz$react.useRef)(initialValue);
24
23
  let handleReset = (0, $1254e5bb94ac8761$exports.useEffectEvent)(()=>{
25
- if (onReset) onReset(resetValue.current);
24
+ if (onReset) onReset(initialValue);
26
25
  });
27
26
  (0, $81vbz$react.useEffect)(()=>{
28
27
  var _ref_current;
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;AAMM,SAAS,0CACd,GAA6F,EAC7F,YAAe,EACf,OAA2B;IAE3B,IAAI,aAAa,CAAA,GAAA,mBAAK,EAAE;IACxB,IAAI,cAAc,CAAA,GAAA,wCAAa,EAAE;QAC/B,IAAI,SACF,QAAQ,WAAW,OAAO;IAE9B;IAEA,CAAA,GAAA,sBAAQ,EAAE;YACG;QAAX,IAAI,OAAO,gBAAA,2BAAA,eAAA,IAAK,OAAO,cAAZ,mCAAA,aAAc,IAAI;QAC7B,iBAAA,2BAAA,KAAM,gBAAgB,CAAC,SAAS;QAChC,OAAO;YACL,iBAAA,2BAAA,KAAM,mBAAmB,CAAC,SAAS;QACrC;IACF,GAAG;QAAC;QAAK;KAAY;AACvB","sources":["packages/@react-aria/utils/src/useFormReset.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {RefObject} from '@react-types/shared';\nimport {useEffect, useRef} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\n\nexport function useFormReset<T>(\n ref: RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null> | undefined,\n initialValue: T,\n onReset: (value: T) => void\n): void {\n let resetValue = useRef(initialValue);\n let handleReset = useEffectEvent(() => {\n if (onReset) {\n onReset(resetValue.current);\n }\n });\n\n useEffect(() => {\n let form = ref?.current?.form;\n form?.addEventListener('reset', handleReset);\n return () => {\n form?.removeEventListener('reset', handleReset);\n };\n }, [ref, handleReset]);\n}\n"],"names":[],"version":3,"file":"useFormReset.main.js.map"}
1
+ {"mappings":";;;;;;;;;AAAA;;;;;;;;;;CAUC;;AAMM,SAAS,0CACd,GAA6F,EAC7F,YAAe,EACf,OAA2B;IAE3B,IAAI,cAAc,CAAA,GAAA,wCAAa,EAAE;QAC/B,IAAI,SACF,QAAQ;IAEZ;IAEA,CAAA,GAAA,sBAAQ,EAAE;YACG;QAAX,IAAI,OAAO,gBAAA,2BAAA,eAAA,IAAK,OAAO,cAAZ,mCAAA,aAAc,IAAI;QAE7B,iBAAA,2BAAA,KAAM,gBAAgB,CAAC,SAAS;QAChC,OAAO;YACL,iBAAA,2BAAA,KAAM,mBAAmB,CAAC,SAAS;QACrC;IACF,GAAG;QAAC;QAAK;KAAY;AACvB","sources":["packages/@react-aria/utils/src/useFormReset.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {RefObject} from '@react-types/shared';\nimport {useEffect} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\n\nexport function useFormReset<T>(\n ref: RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null> | undefined,\n initialValue: T,\n onReset: (value: T) => void\n): void {\n let handleReset = useEffectEvent(() => {\n if (onReset) {\n onReset(initialValue);\n }\n });\n\n useEffect(() => {\n let form = ref?.current?.form;\n\n form?.addEventListener('reset', handleReset);\n return () => {\n form?.removeEventListener('reset', handleReset);\n };\n }, [ref, handleReset]);\n}\n"],"names":[],"version":3,"file":"useFormReset.main.js.map"}
@@ -1,5 +1,5 @@
1
1
  import {useEffectEvent as $8ae05eaa5c114e9c$export$7f54fc3180508a52} from "./useEffectEvent.mjs";
2
- import {useRef as $8rM3G$useRef, useEffect as $8rM3G$useEffect} from "react";
2
+ import {useEffect as $8rM3G$useEffect} from "react";
3
3
 
4
4
  /*
5
5
  * Copyright 2023 Adobe. All rights reserved.
@@ -14,9 +14,8 @@ import {useRef as $8rM3G$useRef, useEffect as $8rM3G$useEffect} from "react";
14
14
  */
15
15
 
16
16
  function $99facab73266f662$export$5add1d006293d136(ref, initialValue, onReset) {
17
- let resetValue = (0, $8rM3G$useRef)(initialValue);
18
17
  let handleReset = (0, $8ae05eaa5c114e9c$export$7f54fc3180508a52)(()=>{
19
- if (onReset) onReset(resetValue.current);
18
+ if (onReset) onReset(initialValue);
20
19
  });
21
20
  (0, $8rM3G$useEffect)(()=>{
22
21
  var _ref_current;
@@ -1,5 +1,5 @@
1
1
  import {useEffectEvent as $8ae05eaa5c114e9c$export$7f54fc3180508a52} from "./useEffectEvent.module.js";
2
- import {useRef as $8rM3G$useRef, useEffect as $8rM3G$useEffect} from "react";
2
+ import {useEffect as $8rM3G$useEffect} from "react";
3
3
 
4
4
  /*
5
5
  * Copyright 2023 Adobe. All rights reserved.
@@ -14,9 +14,8 @@ import {useRef as $8rM3G$useRef, useEffect as $8rM3G$useEffect} from "react";
14
14
  */
15
15
 
16
16
  function $99facab73266f662$export$5add1d006293d136(ref, initialValue, onReset) {
17
- let resetValue = (0, $8rM3G$useRef)(initialValue);
18
17
  let handleReset = (0, $8ae05eaa5c114e9c$export$7f54fc3180508a52)(()=>{
19
- if (onReset) onReset(resetValue.current);
18
+ if (onReset) onReset(initialValue);
20
19
  });
21
20
  (0, $8rM3G$useEffect)(()=>{
22
21
  var _ref_current;
@@ -1 +1 @@
1
- {"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAMM,SAAS,0CACd,GAA6F,EAC7F,YAAe,EACf,OAA2B;IAE3B,IAAI,aAAa,CAAA,GAAA,aAAK,EAAE;IACxB,IAAI,cAAc,CAAA,GAAA,yCAAa,EAAE;QAC/B,IAAI,SACF,QAAQ,WAAW,OAAO;IAE9B;IAEA,CAAA,GAAA,gBAAQ,EAAE;YACG;QAAX,IAAI,OAAO,gBAAA,2BAAA,eAAA,IAAK,OAAO,cAAZ,mCAAA,aAAc,IAAI;QAC7B,iBAAA,2BAAA,KAAM,gBAAgB,CAAC,SAAS;QAChC,OAAO;YACL,iBAAA,2BAAA,KAAM,mBAAmB,CAAC,SAAS;QACrC;IACF,GAAG;QAAC;QAAK;KAAY;AACvB","sources":["packages/@react-aria/utils/src/useFormReset.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {RefObject} from '@react-types/shared';\nimport {useEffect, useRef} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\n\nexport function useFormReset<T>(\n ref: RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null> | undefined,\n initialValue: T,\n onReset: (value: T) => void\n): void {\n let resetValue = useRef(initialValue);\n let handleReset = useEffectEvent(() => {\n if (onReset) {\n onReset(resetValue.current);\n }\n });\n\n useEffect(() => {\n let form = ref?.current?.form;\n form?.addEventListener('reset', handleReset);\n return () => {\n form?.removeEventListener('reset', handleReset);\n };\n }, [ref, handleReset]);\n}\n"],"names":[],"version":3,"file":"useFormReset.module.js.map"}
1
+ {"mappings":";;;AAAA;;;;;;;;;;CAUC;;AAMM,SAAS,0CACd,GAA6F,EAC7F,YAAe,EACf,OAA2B;IAE3B,IAAI,cAAc,CAAA,GAAA,yCAAa,EAAE;QAC/B,IAAI,SACF,QAAQ;IAEZ;IAEA,CAAA,GAAA,gBAAQ,EAAE;YACG;QAAX,IAAI,OAAO,gBAAA,2BAAA,eAAA,IAAK,OAAO,cAAZ,mCAAA,aAAc,IAAI;QAE7B,iBAAA,2BAAA,KAAM,gBAAgB,CAAC,SAAS;QAChC,OAAO;YACL,iBAAA,2BAAA,KAAM,mBAAmB,CAAC,SAAS;QACrC;IACF,GAAG;QAAC;QAAK;KAAY;AACvB","sources":["packages/@react-aria/utils/src/useFormReset.ts"],"sourcesContent":["/*\n * Copyright 2023 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 {RefObject} from '@react-types/shared';\nimport {useEffect} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\n\nexport function useFormReset<T>(\n ref: RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null> | undefined,\n initialValue: T,\n onReset: (value: T) => void\n): void {\n let handleReset = useEffectEvent(() => {\n if (onReset) {\n onReset(initialValue);\n }\n });\n\n useEffect(() => {\n let form = ref?.current?.form;\n\n form?.addEventListener('reset', handleReset);\n return () => {\n form?.removeEventListener('reset', handleReset);\n };\n }, [ref, handleReset]);\n}\n"],"names":[],"version":3,"file":"useFormReset.module.js.map"}
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;CAUC;AAOM,MAAM,4CAAkB,OAAO,aAAa,cAC/C,CAAA,GAAA,sCAAI,EAAE,eAAe,GACrB,KAAO","sources":["packages/@react-aria/utils/src/useLayoutEffect.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 React from 'react';\n\n// During SSR, React emits a warning when calling useLayoutEffect.\n// Since neither useLayoutEffect nor useEffect run on the server,\n// we can suppress this by replace it with a noop on the server.\nexport const useLayoutEffect = typeof document !== 'undefined'\n ? React.useLayoutEffect\n : () => {};\n"],"names":[],"version":3,"file":"useLayoutEffect.main.js.map"}
1
+ {"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;CAUC;AAOM,MAAM,4CAAgD,OAAO,aAAa,cAC7E,CAAA,GAAA,sCAAI,EAAE,eAAe,GACrB,KAAO","sources":["packages/@react-aria/utils/src/useLayoutEffect.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 React from 'react';\n\n// During SSR, React emits a warning when calling useLayoutEffect.\n// Since neither useLayoutEffect nor useEffect run on the server,\n// we can suppress this by replace it with a noop on the server.\nexport const useLayoutEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'\n ? React.useLayoutEffect\n : () => {};\n"],"names":[],"version":3,"file":"useLayoutEffect.main.js.map"}
@@ -1 +1 @@
1
- {"mappings":";;AAAA;;;;;;;;;;CAUC;AAOM,MAAM,4CAAkB,OAAO,aAAa,cAC/C,CAAA,GAAA,YAAI,EAAE,eAAe,GACrB,KAAO","sources":["packages/@react-aria/utils/src/useLayoutEffect.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 React from 'react';\n\n// During SSR, React emits a warning when calling useLayoutEffect.\n// Since neither useLayoutEffect nor useEffect run on the server,\n// we can suppress this by replace it with a noop on the server.\nexport const useLayoutEffect = typeof document !== 'undefined'\n ? React.useLayoutEffect\n : () => {};\n"],"names":[],"version":3,"file":"useLayoutEffect.module.js.map"}
1
+ {"mappings":";;AAAA;;;;;;;;;;CAUC;AAOM,MAAM,4CAAgD,OAAO,aAAa,cAC7E,CAAA,GAAA,YAAI,EAAE,eAAe,GACrB,KAAO","sources":["packages/@react-aria/utils/src/useLayoutEffect.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 React from 'react';\n\n// During SSR, React emits a warning when calling useLayoutEffect.\n// Since neither useLayoutEffect nor useEffect run on the server,\n// we can suppress this by replace it with a noop on the server.\nexport const useLayoutEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'\n ? React.useLayoutEffect\n : () => {};\n"],"names":[],"version":3,"file":"useLayoutEffect.module.js.map"}
@@ -8,7 +8,7 @@ function $parcel$export(e, n, v, s) {
8
8
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
9
9
  }
10
10
 
11
- $parcel$export(module.exports, "UNSTABLE_useLoadMoreSentinel", () => $f6a4874a7c582761$export$90a12e6abf95cbe0);
11
+ $parcel$export(module.exports, "useLoadMoreSentinel", () => $f6a4874a7c582761$export$ccaea96c28e8b9e7);
12
12
  /*
13
13
  * Copyright 2024 Adobe. All rights reserved.
14
14
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@ $parcel$export(module.exports, "UNSTABLE_useLoadMoreSentinel", () => $f6a4874a7c
23
23
 
24
24
 
25
25
 
26
- function $f6a4874a7c582761$export$90a12e6abf95cbe0(props, ref) {
26
+ function $f6a4874a7c582761$export$ccaea96c28e8b9e7(props, ref) {
27
27
  let { collection: collection, onLoadMore: onLoadMore, scrollOffset: scrollOffset = 1 } = props;
28
28
  let sentinelObserver = (0, $8Ncyo$react.useRef)(null);
29
29
  let triggerLoadMore = (0, $1254e5bb94ac8761$exports.useEffectEvent)((entries)=>{
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;AAoBM,SAAS,0CAA6B,KAA4B,EAAE,GAAkC;IAC3G,IAAI,cAAC,UAAU,cAAE,UAAU,gBAAE,eAAe,GAAE,GAAG;IAEjD,IAAI,mBAAmB,CAAA,GAAA,mBAAK,EAAwB;IAEpD,IAAI,kBAAkB,CAAA,GAAA,wCAAa,EAAE,CAAC;QACpC,4FAA4F;QAC5F,iFAAiF;QACjF,KAAK,IAAI,SAAS,QAChB,yHAAyH;QACzH,4EAA4E;QAC5E,IAAI,MAAM,cAAc,IAAI,YAC1B;IAGN;IAEA,CAAA,GAAA,yCAAc,EAAE;QACd,IAAI,IAAI,OAAO,EAAE;YACf,mKAAmK;YACnK,0MAA0M;YAC1M,yFAAyF;YACzF,iBAAiB,OAAO,GAAG,IAAI,qBAAqB,iBAAiB;gBAAC,MAAM,CAAA,GAAA,yCAAc,EAAE,gBAAA,0BAAA,IAAK,OAAO;gBAAkB,YAAY,CAAC,IAAI,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,CAAC,CAAC;YAAA;YAChN,iBAAiB,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO;QAC9C;QAEA,OAAO;YACL,IAAI,iBAAiB,OAAO,EAC1B,iBAAiB,OAAO,CAAC,UAAU;QAEvC;IACF,GAAG;QAAC;QAAY;QAAiB;QAAK;KAAa;AACrD","sources":["packages/@react-aria/utils/src/useLoadMoreSentinel.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 type {AsyncLoadable, Collection, Node} from '@react-types/shared';\nimport {getScrollParent} from './getScrollParent';\nimport {RefObject, useRef} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\nimport {useLayoutEffect} from './useLayoutEffect';\n\nexport interface LoadMoreSentinelProps extends Omit<AsyncLoadable, 'isLoading'> {\n collection: Collection<Node<unknown>>,\n /**\n * The amount of offset from the bottom of your scrollable region that should trigger load more.\n * Uses a percentage value relative to the scroll body's client height. Load more is then triggered\n * when your current scroll position's distance from the bottom of the currently loaded list of items is less than\n * or equal to the provided value. (e.g. 1 = 100% of the scroll region's height).\n * @default 1\n */\n scrollOffset?: number\n}\n\nexport function UNSTABLE_useLoadMoreSentinel(props: LoadMoreSentinelProps, ref: RefObject<HTMLElement | null>): void {\n let {collection, onLoadMore, scrollOffset = 1} = props;\n\n let sentinelObserver = useRef<IntersectionObserver>(null);\n\n let triggerLoadMore = useEffectEvent((entries: IntersectionObserverEntry[]) => {\n // Use \"isIntersecting\" over an equality check of 0 since it seems like there is cases where\n // a intersection ratio of 0 can be reported when isIntersecting is actually true\n for (let entry of entries) {\n // Note that this will be called if the collection changes, even if onLoadMore was already called and is being processed.\n // Up to user discretion as to how to handle these multiple onLoadMore calls\n if (entry.isIntersecting && onLoadMore) {\n onLoadMore();\n }\n }\n });\n\n useLayoutEffect(() => {\n if (ref.current) {\n // Tear down and set up a new IntersectionObserver when the collection changes so that we can properly trigger additional loadMores if there is room for more items\n // Need to do this tear down and set up since using a large rootMargin will mean the observer's callback isn't called even when scrolling the item into view beause its visibility hasn't actually changed\n // https://codesandbox.io/p/sandbox/magical-swanson-dhgp89?file=%2Fsrc%2FApp.js%3A21%2C21\n sentinelObserver.current = new IntersectionObserver(triggerLoadMore, {root: getScrollParent(ref?.current) as HTMLElement, rootMargin: `0px ${100 * scrollOffset}% ${100 * scrollOffset}% ${100 * scrollOffset}%`});\n sentinelObserver.current.observe(ref.current);\n }\n\n return () => {\n if (sentinelObserver.current) {\n sentinelObserver.current.disconnect();\n }\n };\n }, [collection, triggerLoadMore, ref, scrollOffset]);\n}\n"],"names":[],"version":3,"file":"useLoadMoreSentinel.main.js.map"}
1
+ {"mappings":";;;;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;AAoBM,SAAS,0CAAoB,KAA4B,EAAE,GAAkC;IAClG,IAAI,cAAC,UAAU,cAAE,UAAU,gBAAE,eAAe,GAAE,GAAG;IAEjD,IAAI,mBAAmB,CAAA,GAAA,mBAAK,EAAwB;IAEpD,IAAI,kBAAkB,CAAA,GAAA,wCAAa,EAAE,CAAC;QACpC,4FAA4F;QAC5F,iFAAiF;QACjF,KAAK,IAAI,SAAS,QAChB,yHAAyH;QACzH,4EAA4E;QAC5E,IAAI,MAAM,cAAc,IAAI,YAC1B;IAGN;IAEA,CAAA,GAAA,yCAAc,EAAE;QACd,IAAI,IAAI,OAAO,EAAE;YACf,mKAAmK;YACnK,0MAA0M;YAC1M,yFAAyF;YACzF,iBAAiB,OAAO,GAAG,IAAI,qBAAqB,iBAAiB;gBAAC,MAAM,CAAA,GAAA,yCAAc,EAAE,gBAAA,0BAAA,IAAK,OAAO;gBAAkB,YAAY,CAAC,IAAI,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,CAAC,CAAC;YAAA;YAChN,iBAAiB,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO;QAC9C;QAEA,OAAO;YACL,IAAI,iBAAiB,OAAO,EAC1B,iBAAiB,OAAO,CAAC,UAAU;QAEvC;IACF,GAAG;QAAC;QAAY;QAAiB;QAAK;KAAa;AACrD","sources":["packages/@react-aria/utils/src/useLoadMoreSentinel.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 type {AsyncLoadable, Collection} from '@react-types/shared';\nimport {getScrollParent} from './getScrollParent';\nimport {RefObject, useRef} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\nimport {useLayoutEffect} from './useLayoutEffect';\n\nexport interface LoadMoreSentinelProps extends Omit<AsyncLoadable, 'isLoading'> {\n collection: Collection<any>,\n /**\n * The amount of offset from the bottom of your scrollable region that should trigger load more.\n * Uses a percentage value relative to the scroll body's client height. Load more is then triggered\n * when your current scroll position's distance from the bottom of the currently loaded list of items is less than\n * or equal to the provided value. (e.g. 1 = 100% of the scroll region's height).\n * @default 1\n */\n scrollOffset?: number\n}\n\nexport function useLoadMoreSentinel(props: LoadMoreSentinelProps, ref: RefObject<HTMLElement | null>): void {\n let {collection, onLoadMore, scrollOffset = 1} = props;\n\n let sentinelObserver = useRef<IntersectionObserver>(null);\n\n let triggerLoadMore = useEffectEvent((entries: IntersectionObserverEntry[]) => {\n // Use \"isIntersecting\" over an equality check of 0 since it seems like there is cases where\n // a intersection ratio of 0 can be reported when isIntersecting is actually true\n for (let entry of entries) {\n // Note that this will be called if the collection changes, even if onLoadMore was already called and is being processed.\n // Up to user discretion as to how to handle these multiple onLoadMore calls\n if (entry.isIntersecting && onLoadMore) {\n onLoadMore();\n }\n }\n });\n\n useLayoutEffect(() => {\n if (ref.current) {\n // Tear down and set up a new IntersectionObserver when the collection changes so that we can properly trigger additional loadMores if there is room for more items\n // Need to do this tear down and set up since using a large rootMargin will mean the observer's callback isn't called even when scrolling the item into view beause its visibility hasn't actually changed\n // https://codesandbox.io/p/sandbox/magical-swanson-dhgp89?file=%2Fsrc%2FApp.js%3A21%2C21\n sentinelObserver.current = new IntersectionObserver(triggerLoadMore, {root: getScrollParent(ref?.current) as HTMLElement, rootMargin: `0px ${100 * scrollOffset}% ${100 * scrollOffset}% ${100 * scrollOffset}%`});\n sentinelObserver.current.observe(ref.current);\n }\n\n return () => {\n if (sentinelObserver.current) {\n sentinelObserver.current.disconnect();\n }\n };\n }, [collection, triggerLoadMore, ref, scrollOffset]);\n}\n"],"names":[],"version":3,"file":"useLoadMoreSentinel.main.js.map"}
@@ -17,7 +17,7 @@ import {useRef as $7FoZl$useRef} from "react";
17
17
 
18
18
 
19
19
 
20
- function $a5fa973c1850dd36$export$90a12e6abf95cbe0(props, ref) {
20
+ function $a5fa973c1850dd36$export$ccaea96c28e8b9e7(props, ref) {
21
21
  let { collection: collection, onLoadMore: onLoadMore, scrollOffset: scrollOffset = 1 } = props;
22
22
  let sentinelObserver = (0, $7FoZl$useRef)(null);
23
23
  let triggerLoadMore = (0, $8ae05eaa5c114e9c$export$7f54fc3180508a52)((entries)=>{
@@ -50,5 +50,5 @@ function $a5fa973c1850dd36$export$90a12e6abf95cbe0(props, ref) {
50
50
  }
51
51
 
52
52
 
53
- export {$a5fa973c1850dd36$export$90a12e6abf95cbe0 as UNSTABLE_useLoadMoreSentinel};
53
+ export {$a5fa973c1850dd36$export$ccaea96c28e8b9e7 as useLoadMoreSentinel};
54
54
  //# sourceMappingURL=useLoadMoreSentinel.module.js.map
@@ -17,7 +17,7 @@ import {useRef as $7FoZl$useRef} from "react";
17
17
 
18
18
 
19
19
 
20
- function $a5fa973c1850dd36$export$90a12e6abf95cbe0(props, ref) {
20
+ function $a5fa973c1850dd36$export$ccaea96c28e8b9e7(props, ref) {
21
21
  let { collection: collection, onLoadMore: onLoadMore, scrollOffset: scrollOffset = 1 } = props;
22
22
  let sentinelObserver = (0, $7FoZl$useRef)(null);
23
23
  let triggerLoadMore = (0, $8ae05eaa5c114e9c$export$7f54fc3180508a52)((entries)=>{
@@ -50,5 +50,5 @@ function $a5fa973c1850dd36$export$90a12e6abf95cbe0(props, ref) {
50
50
  }
51
51
 
52
52
 
53
- export {$a5fa973c1850dd36$export$90a12e6abf95cbe0 as UNSTABLE_useLoadMoreSentinel};
53
+ export {$a5fa973c1850dd36$export$ccaea96c28e8b9e7 as useLoadMoreSentinel};
54
54
  //# sourceMappingURL=useLoadMoreSentinel.module.js.map
@@ -1 +1 @@
1
- {"mappings":";;;;;AAAA;;;;;;;;;;CAUC;;;;AAoBM,SAAS,0CAA6B,KAA4B,EAAE,GAAkC;IAC3G,IAAI,cAAC,UAAU,cAAE,UAAU,gBAAE,eAAe,GAAE,GAAG;IAEjD,IAAI,mBAAmB,CAAA,GAAA,aAAK,EAAwB;IAEpD,IAAI,kBAAkB,CAAA,GAAA,yCAAa,EAAE,CAAC;QACpC,4FAA4F;QAC5F,iFAAiF;QACjF,KAAK,IAAI,SAAS,QAChB,yHAAyH;QACzH,4EAA4E;QAC5E,IAAI,MAAM,cAAc,IAAI,YAC1B;IAGN;IAEA,CAAA,GAAA,yCAAc,EAAE;QACd,IAAI,IAAI,OAAO,EAAE;YACf,mKAAmK;YACnK,0MAA0M;YAC1M,yFAAyF;YACzF,iBAAiB,OAAO,GAAG,IAAI,qBAAqB,iBAAiB;gBAAC,MAAM,CAAA,GAAA,yCAAc,EAAE,gBAAA,0BAAA,IAAK,OAAO;gBAAkB,YAAY,CAAC,IAAI,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,CAAC,CAAC;YAAA;YAChN,iBAAiB,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO;QAC9C;QAEA,OAAO;YACL,IAAI,iBAAiB,OAAO,EAC1B,iBAAiB,OAAO,CAAC,UAAU;QAEvC;IACF,GAAG;QAAC;QAAY;QAAiB;QAAK;KAAa;AACrD","sources":["packages/@react-aria/utils/src/useLoadMoreSentinel.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 type {AsyncLoadable, Collection, Node} from '@react-types/shared';\nimport {getScrollParent} from './getScrollParent';\nimport {RefObject, useRef} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\nimport {useLayoutEffect} from './useLayoutEffect';\n\nexport interface LoadMoreSentinelProps extends Omit<AsyncLoadable, 'isLoading'> {\n collection: Collection<Node<unknown>>,\n /**\n * The amount of offset from the bottom of your scrollable region that should trigger load more.\n * Uses a percentage value relative to the scroll body's client height. Load more is then triggered\n * when your current scroll position's distance from the bottom of the currently loaded list of items is less than\n * or equal to the provided value. (e.g. 1 = 100% of the scroll region's height).\n * @default 1\n */\n scrollOffset?: number\n}\n\nexport function UNSTABLE_useLoadMoreSentinel(props: LoadMoreSentinelProps, ref: RefObject<HTMLElement | null>): void {\n let {collection, onLoadMore, scrollOffset = 1} = props;\n\n let sentinelObserver = useRef<IntersectionObserver>(null);\n\n let triggerLoadMore = useEffectEvent((entries: IntersectionObserverEntry[]) => {\n // Use \"isIntersecting\" over an equality check of 0 since it seems like there is cases where\n // a intersection ratio of 0 can be reported when isIntersecting is actually true\n for (let entry of entries) {\n // Note that this will be called if the collection changes, even if onLoadMore was already called and is being processed.\n // Up to user discretion as to how to handle these multiple onLoadMore calls\n if (entry.isIntersecting && onLoadMore) {\n onLoadMore();\n }\n }\n });\n\n useLayoutEffect(() => {\n if (ref.current) {\n // Tear down and set up a new IntersectionObserver when the collection changes so that we can properly trigger additional loadMores if there is room for more items\n // Need to do this tear down and set up since using a large rootMargin will mean the observer's callback isn't called even when scrolling the item into view beause its visibility hasn't actually changed\n // https://codesandbox.io/p/sandbox/magical-swanson-dhgp89?file=%2Fsrc%2FApp.js%3A21%2C21\n sentinelObserver.current = new IntersectionObserver(triggerLoadMore, {root: getScrollParent(ref?.current) as HTMLElement, rootMargin: `0px ${100 * scrollOffset}% ${100 * scrollOffset}% ${100 * scrollOffset}%`});\n sentinelObserver.current.observe(ref.current);\n }\n\n return () => {\n if (sentinelObserver.current) {\n sentinelObserver.current.disconnect();\n }\n };\n }, [collection, triggerLoadMore, ref, scrollOffset]);\n}\n"],"names":[],"version":3,"file":"useLoadMoreSentinel.module.js.map"}
1
+ {"mappings":";;;;;AAAA;;;;;;;;;;CAUC;;;;AAoBM,SAAS,0CAAoB,KAA4B,EAAE,GAAkC;IAClG,IAAI,cAAC,UAAU,cAAE,UAAU,gBAAE,eAAe,GAAE,GAAG;IAEjD,IAAI,mBAAmB,CAAA,GAAA,aAAK,EAAwB;IAEpD,IAAI,kBAAkB,CAAA,GAAA,yCAAa,EAAE,CAAC;QACpC,4FAA4F;QAC5F,iFAAiF;QACjF,KAAK,IAAI,SAAS,QAChB,yHAAyH;QACzH,4EAA4E;QAC5E,IAAI,MAAM,cAAc,IAAI,YAC1B;IAGN;IAEA,CAAA,GAAA,yCAAc,EAAE;QACd,IAAI,IAAI,OAAO,EAAE;YACf,mKAAmK;YACnK,0MAA0M;YAC1M,yFAAyF;YACzF,iBAAiB,OAAO,GAAG,IAAI,qBAAqB,iBAAiB;gBAAC,MAAM,CAAA,GAAA,yCAAc,EAAE,gBAAA,0BAAA,IAAK,OAAO;gBAAkB,YAAY,CAAC,IAAI,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,EAAE,EAAE,MAAM,aAAa,CAAC,CAAC;YAAA;YAChN,iBAAiB,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO;QAC9C;QAEA,OAAO;YACL,IAAI,iBAAiB,OAAO,EAC1B,iBAAiB,OAAO,CAAC,UAAU;QAEvC;IACF,GAAG;QAAC;QAAY;QAAiB;QAAK;KAAa;AACrD","sources":["packages/@react-aria/utils/src/useLoadMoreSentinel.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 type {AsyncLoadable, Collection} from '@react-types/shared';\nimport {getScrollParent} from './getScrollParent';\nimport {RefObject, useRef} from 'react';\nimport {useEffectEvent} from './useEffectEvent';\nimport {useLayoutEffect} from './useLayoutEffect';\n\nexport interface LoadMoreSentinelProps extends Omit<AsyncLoadable, 'isLoading'> {\n collection: Collection<any>,\n /**\n * The amount of offset from the bottom of your scrollable region that should trigger load more.\n * Uses a percentage value relative to the scroll body's client height. Load more is then triggered\n * when your current scroll position's distance from the bottom of the currently loaded list of items is less than\n * or equal to the provided value. (e.g. 1 = 100% of the scroll region's height).\n * @default 1\n */\n scrollOffset?: number\n}\n\nexport function useLoadMoreSentinel(props: LoadMoreSentinelProps, ref: RefObject<HTMLElement | null>): void {\n let {collection, onLoadMore, scrollOffset = 1} = props;\n\n let sentinelObserver = useRef<IntersectionObserver>(null);\n\n let triggerLoadMore = useEffectEvent((entries: IntersectionObserverEntry[]) => {\n // Use \"isIntersecting\" over an equality check of 0 since it seems like there is cases where\n // a intersection ratio of 0 can be reported when isIntersecting is actually true\n for (let entry of entries) {\n // Note that this will be called if the collection changes, even if onLoadMore was already called and is being processed.\n // Up to user discretion as to how to handle these multiple onLoadMore calls\n if (entry.isIntersecting && onLoadMore) {\n onLoadMore();\n }\n }\n });\n\n useLayoutEffect(() => {\n if (ref.current) {\n // Tear down and set up a new IntersectionObserver when the collection changes so that we can properly trigger additional loadMores if there is room for more items\n // Need to do this tear down and set up since using a large rootMargin will mean the observer's callback isn't called even when scrolling the item into view beause its visibility hasn't actually changed\n // https://codesandbox.io/p/sandbox/magical-swanson-dhgp89?file=%2Fsrc%2FApp.js%3A21%2C21\n sentinelObserver.current = new IntersectionObserver(triggerLoadMore, {root: getScrollParent(ref?.current) as HTMLElement, rootMargin: `0px ${100 * scrollOffset}% ${100 * scrollOffset}% ${100 * scrollOffset}%`});\n sentinelObserver.current.observe(ref.current);\n }\n\n return () => {\n if (sentinelObserver.current) {\n sentinelObserver.current.disconnect();\n }\n };\n }, [collection, triggerLoadMore, ref, scrollOffset]);\n}\n"],"names":[],"version":3,"file":"useLoadMoreSentinel.module.js.map"}
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@react-aria/utils",
3
- "version": "3.29.0",
3
+ "version": "3.30.0",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
7
7
  "module": "dist/module.js",
8
8
  "exports": {
9
- "types": "./dist/types.d.ts",
9
+ "source": "./src/index.ts",
10
+ "types": [
11
+ "./dist/types.d.ts",
12
+ "./src/index.ts"
13
+ ],
10
14
  "import": "./dist/import.mjs",
11
15
  "require": "./dist/main.js"
12
16
  },
@@ -22,10 +26,10 @@
22
26
  "url": "https://github.com/adobe/react-spectrum"
23
27
  },
24
28
  "dependencies": {
25
- "@react-aria/ssr": "^3.9.8",
26
- "@react-stately/flags": "^3.1.1",
27
- "@react-stately/utils": "^3.10.6",
28
- "@react-types/shared": "^3.29.1",
29
+ "@react-aria/ssr": "^3.9.10",
30
+ "@react-stately/flags": "^3.1.2",
31
+ "@react-stately/utils": "^3.10.8",
32
+ "@react-types/shared": "^3.31.0",
29
33
  "@swc/helpers": "^0.5.0",
30
34
  "clsx": "^2.0.0"
31
35
  },
@@ -36,5 +40,5 @@
36
40
  "publishConfig": {
37
41
  "access": "public"
38
42
  },
39
- "gitHead": "9c77d4e8267ed39469c65f65da94ece7be509874"
43
+ "gitHead": "8b9348ff255e018b2dd9b27e2a45507cadfa1d35"
40
44
  }
@@ -10,7 +10,7 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {AriaLabelingProps, DOMProps, LinkDOMProps} from '@react-types/shared';
13
+ import {AriaLabelingProps, DOMProps, GlobalDOMAttributes, LinkDOMProps} from '@react-types/shared';
14
14
 
15
15
  const DOMPropNames = new Set([
16
16
  'id'
@@ -34,6 +34,51 @@ const linkPropNames = new Set([
34
34
  'referrerPolicy'
35
35
  ]);
36
36
 
37
+ const globalAttrs = new Set([
38
+ 'dir',
39
+ 'lang',
40
+ 'hidden',
41
+ 'inert',
42
+ 'translate'
43
+ ]);
44
+
45
+ const globalEvents = new Set([
46
+ 'onClick',
47
+ 'onAuxClick',
48
+ 'onContextMenu',
49
+ 'onDoubleClick',
50
+ 'onMouseDown',
51
+ 'onMouseEnter',
52
+ 'onMouseLeave',
53
+ 'onMouseMove',
54
+ 'onMouseOut',
55
+ 'onMouseOver',
56
+ 'onMouseUp',
57
+ 'onTouchCancel',
58
+ 'onTouchEnd',
59
+ 'onTouchMove',
60
+ 'onTouchStart',
61
+ 'onPointerDown',
62
+ 'onPointerMove',
63
+ 'onPointerUp',
64
+ 'onPointerCancel',
65
+ 'onPointerEnter',
66
+ 'onPointerLeave',
67
+ 'onPointerOver',
68
+ 'onPointerOut',
69
+ 'onGotPointerCapture',
70
+ 'onLostPointerCapture',
71
+ 'onScroll',
72
+ 'onWheel',
73
+ 'onAnimationStart',
74
+ 'onAnimationEnd',
75
+ 'onAnimationIteration',
76
+ 'onTransitionCancel',
77
+ 'onTransitionEnd',
78
+ 'onTransitionRun',
79
+ 'onTransitionStart'
80
+ ]);
81
+
37
82
  interface Options {
38
83
  /**
39
84
  * If labelling associated aria properties should be included in the filter.
@@ -41,6 +86,10 @@ interface Options {
41
86
  labelable?: boolean,
42
87
  /** Whether the element is a link and should include DOM props for <a> elements. */
43
88
  isLink?: boolean,
89
+ /** Whether to include global DOM attributes. */
90
+ global?: boolean,
91
+ /** Whether to include DOM events. */
92
+ events?: boolean,
44
93
  /**
45
94
  * A Set of other property names that should be included in the filter.
46
95
  */
@@ -54,8 +103,8 @@ const propRe = /^(data-.*)$/;
54
103
  * @param props - The component props to be filtered.
55
104
  * @param opts - Props to override.
56
105
  */
57
- export function filterDOMProps(props: DOMProps & AriaLabelingProps & LinkDOMProps, opts: Options = {}): DOMProps & AriaLabelingProps {
58
- let {labelable, isLink, propNames} = opts;
106
+ export function filterDOMProps(props: DOMProps & AriaLabelingProps & LinkDOMProps & GlobalDOMAttributes, opts: Options = {}): DOMProps & AriaLabelingProps & GlobalDOMAttributes {
107
+ let {labelable, isLink, global, events = global, propNames} = opts;
59
108
  let filteredProps = {};
60
109
 
61
110
  for (const prop in props) {
@@ -64,6 +113,8 @@ export function filterDOMProps(props: DOMProps & AriaLabelingProps & LinkDOMProp
64
113
  DOMPropNames.has(prop) ||
65
114
  (labelable && labelablePropNames.has(prop)) ||
66
115
  (isLink && linkPropNames.has(prop)) ||
116
+ (global && globalAttrs.has(prop)) ||
117
+ (events && globalEvents.has(prop) || (prop.endsWith('Capture') && globalEvents.has(prop.slice(0, -7)))) ||
67
118
  propNames?.has(prop) ||
68
119
  propRe.test(prop)
69
120
  )
package/src/index.ts CHANGED
@@ -19,7 +19,7 @@ export {mergeRefs} from './mergeRefs';
19
19
  export {filterDOMProps} from './filterDOMProps';
20
20
  export {focusWithoutScrolling} from './focusWithoutScrolling';
21
21
  export {getOffset} from './getOffset';
22
- export {openLink, getSyntheticLinkProps, useSyntheticLinkProps, RouterProvider, shouldClientNavigate, useRouter, useLinkProps} from './openLink';
22
+ export {openLink, getSyntheticLinkProps, useSyntheticLinkProps, RouterProvider, shouldClientNavigate, useRouter, useLinkProps, handleLinkClick} from './openLink';
23
23
  export {runAfterTransition} from './runAfterTransition';
24
24
  export {useDrag1D} from './useDrag1D';
25
25
  export {useGlobalListeners} from './useGlobalListeners';
@@ -45,7 +45,7 @@ export {useEffectEvent} from './useEffectEvent';
45
45
  export {useDeepMemo} from './useDeepMemo';
46
46
  export {useFormReset} from './useFormReset';
47
47
  export {useLoadMore} from './useLoadMore';
48
- export {UNSTABLE_useLoadMoreSentinel} from './useLoadMoreSentinel';
48
+ export {useLoadMoreSentinel} from './useLoadMoreSentinel';
49
49
  export {inertValue} from './inertValue';
50
50
  export {CLEAR_FOCUS_EVENT, FOCUS_EVENT} from './constants';
51
51
  export {isCtrlKeyPressed} from './keyboard';
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Copyright 2021 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 {getOwnerWindow} from './domHelpers';
14
+
15
+ const supportsCheckVisibility = typeof Element !== 'undefined' && 'checkVisibility' in Element.prototype;
16
+
17
+ function isStyleVisible(element: Element) {
18
+ const windowObject = getOwnerWindow(element);
19
+ if (!(element instanceof windowObject.HTMLElement) && !(element instanceof windowObject.SVGElement)) {
20
+ return false;
21
+ }
22
+
23
+ let {display, visibility} = element.style;
24
+
25
+ let isVisible = (
26
+ display !== 'none' &&
27
+ visibility !== 'hidden' &&
28
+ visibility !== 'collapse'
29
+ );
30
+
31
+ if (isVisible) {
32
+ const {getComputedStyle} = element.ownerDocument.defaultView as unknown as Window;
33
+ let {display: computedDisplay, visibility: computedVisibility} = getComputedStyle(element);
34
+
35
+ isVisible = (
36
+ computedDisplay !== 'none' &&
37
+ computedVisibility !== 'hidden' &&
38
+ computedVisibility !== 'collapse'
39
+ );
40
+ }
41
+
42
+ return isVisible;
43
+ }
44
+
45
+ function isAttributeVisible(element: Element, childElement?: Element) {
46
+ return (
47
+ !element.hasAttribute('hidden') &&
48
+ // Ignore HiddenSelect when tree walking.
49
+ !element.hasAttribute('data-react-aria-prevent-focus') &&
50
+ (element.nodeName === 'DETAILS' &&
51
+ childElement &&
52
+ childElement.nodeName !== 'SUMMARY'
53
+ ? element.hasAttribute('open')
54
+ : true)
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Adapted from https://github.com/testing-library/jest-dom and
60
+ * https://github.com/vuejs/vue-test-utils-next/.
61
+ * Licensed under the MIT License.
62
+ * @param element - Element to evaluate for display or visibility.
63
+ */
64
+ export function isElementVisible(element: Element, childElement?: Element): boolean {
65
+ if (supportsCheckVisibility) {
66
+ return element.checkVisibility();
67
+ }
68
+
69
+ return (
70
+ element.nodeName !== '#comment' &&
71
+ isStyleVisible(element) &&
72
+ isAttributeVisible(element, childElement) &&
73
+ (!element.parentElement || isElementVisible(element.parentElement, element))
74
+ );
75
+ }
@@ -1,3 +1,17 @@
1
+ /*
2
+ * Copyright 2025 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 {isElementVisible} from './isElementVisible';
14
+
1
15
  const focusableElements = [
2
16
  'input:not([disabled]):not([type=hidden])',
3
17
  'select:not([disabled])',
@@ -11,7 +25,8 @@ const focusableElements = [
11
25
  'embed',
12
26
  'audio[controls]',
13
27
  'video[controls]',
14
- '[contenteditable]:not([contenteditable^="false"])'
28
+ '[contenteditable]:not([contenteditable^="false"])',
29
+ 'permission'
15
30
  ];
16
31
 
17
32
  const FOCUSABLE_ELEMENT_SELECTOR = focusableElements.join(':not([hidden]),') + ',[tabindex]:not([disabled]):not([hidden])';
@@ -20,9 +35,22 @@ focusableElements.push('[tabindex]:not([tabindex="-1"]):not([disabled])');
20
35
  const TABBABLE_ELEMENT_SELECTOR = focusableElements.join(':not([hidden]):not([tabindex="-1"]),');
21
36
 
22
37
  export function isFocusable(element: Element): boolean {
23
- return element.matches(FOCUSABLE_ELEMENT_SELECTOR);
38
+ return element.matches(FOCUSABLE_ELEMENT_SELECTOR) && isElementVisible(element) && !isInert(element);
24
39
  }
25
40
 
26
41
  export function isTabbable(element: Element): boolean {
27
- return element.matches(TABBABLE_ELEMENT_SELECTOR);
42
+ return element.matches(TABBABLE_ELEMENT_SELECTOR) && isElementVisible(element) && !isInert(element);
43
+ }
44
+
45
+ function isInert(element: Element): boolean {
46
+ let node: Element | null = element;
47
+ while (node != null) {
48
+ if (node instanceof node.ownerDocument.defaultView!.HTMLElement && node.inert) {
49
+ return true;
50
+ }
51
+
52
+ node = node.parentElement;
53
+ }
54
+
55
+ return false;
28
56
  }
package/src/openLink.tsx CHANGED
@@ -13,7 +13,7 @@
13
13
  import {focusWithoutScrolling, isMac, isWebKit} from './index';
14
14
  import {Href, LinkDOMProps, RouterOptions} from '@react-types/shared';
15
15
  import {isFirefox, isIPad} from './platform';
16
- import React, {createContext, DOMAttributes, JSX, ReactNode, useContext, useMemo} from 'react';
16
+ import React, {createContext, DOMAttributes, JSX, MouseEvent as ReactMouseEvent, ReactNode, useContext, useMemo} from 'react';
17
17
 
18
18
  interface Router {
19
19
  isNative: boolean,
@@ -183,3 +183,19 @@ export function useLinkProps(props?: LinkDOMProps): LinkDOMProps {
183
183
  referrerPolicy: props?.referrerPolicy
184
184
  };
185
185
  }
186
+
187
+ export function handleLinkClick(e: ReactMouseEvent, router: Router, href: Href | undefined, routerOptions: RouterOptions | undefined): void {
188
+ // If a custom router is provided, prevent default and forward if this link should client navigate.
189
+ if (
190
+ !router.isNative &&
191
+ e.currentTarget instanceof HTMLAnchorElement &&
192
+ e.currentTarget.href &&
193
+ // If props are applied to a router Link component, it may have already prevented default.
194
+ !e.isDefaultPrevented() &&
195
+ shouldClientNavigate(e.currentTarget, e) &&
196
+ href
197
+ ) {
198
+ e.preventDefault();
199
+ router.open(e.currentTarget, e, href, routerOptions);
200
+ }
201
+ }
package/src/platform.ts CHANGED
@@ -14,10 +14,9 @@ function testUserAgent(re: RegExp) {
14
14
  if (typeof window === 'undefined' || window.navigator == null) {
15
15
  return false;
16
16
  }
17
- return (
18
- window.navigator['userAgentData']?.brands.some((brand: {brand: string, version: string}) => re.test(brand.brand))
19
- ) ||
20
- re.test(window.navigator.userAgent);
17
+ let brands = window.navigator['userAgentData']?.brands;
18
+ return Array.isArray(brands) && brands.some((brand: {brand: string, version: string}) => re.test(brand.brand)) ||
19
+ re.test(window.navigator.userAgent);
21
20
  }
22
21
 
23
22
  function testPlatform(re: RegExp) {
@@ -30,7 +29,7 @@ function cached(fn: () => boolean) {
30
29
  if (process.env.NODE_ENV === 'test') {
31
30
  return fn;
32
31
  }
33
-
32
+
34
33
  let res: boolean | null = null;
35
34
  return () => {
36
35
  if (res == null) {
@@ -40,40 +39,40 @@ function cached(fn: () => boolean) {
40
39
  };
41
40
  }
42
41
 
43
- export const isMac = cached(function () {
42
+ export const isMac: () => boolean = cached(function () {
44
43
  return testPlatform(/^Mac/i);
45
44
  });
46
45
 
47
- export const isIPhone = cached(function () {
46
+ export const isIPhone: () => boolean = cached(function () {
48
47
  return testPlatform(/^iPhone/i);
49
48
  });
50
49
 
51
- export const isIPad = cached(function () {
50
+ export const isIPad: () => boolean = cached(function () {
52
51
  return testPlatform(/^iPad/i) ||
53
52
  // iPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
54
53
  (isMac() && navigator.maxTouchPoints > 1);
55
54
  });
56
55
 
57
- export const isIOS = cached(function () {
56
+ export const isIOS: () => boolean = cached(function () {
58
57
  return isIPhone() || isIPad();
59
58
  });
60
59
 
61
- export const isAppleDevice = cached(function () {
60
+ export const isAppleDevice: () => boolean = cached(function () {
62
61
  return isMac() || isIOS();
63
62
  });
64
63
 
65
- export const isWebKit = cached(function () {
64
+ export const isWebKit: () => boolean = cached(function () {
66
65
  return testUserAgent(/AppleWebKit/i) && !isChrome();
67
66
  });
68
67
 
69
- export const isChrome = cached(function () {
68
+ export const isChrome: () => boolean = cached(function () {
70
69
  return testUserAgent(/Chrome/i);
71
70
  });
72
71
 
73
- export const isAndroid = cached(function () {
72
+ export const isAndroid: () => boolean = cached(function () {
74
73
  return testUserAgent(/Android/i);
75
74
  });
76
75
 
77
- export const isFirefox = cached(function () {
76
+ export const isFirefox: () => boolean = cached(function () {
78
77
  return testUserAgent(/Firefox/i);
79
78
  });
@@ -10,12 +10,16 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {useCallback, useRef} from 'react';
13
+ import React, {useCallback, useRef} from 'react';
14
14
  import {useLayoutEffect} from './useLayoutEffect';
15
15
 
16
+ // Use the earliest effect type possible. useInsertionEffect runs during the mutation phase,
17
+ // before all layout effects, but is available only in React 18 and later.
18
+ const useEarlyEffect = React['useInsertionEffect'] ?? useLayoutEffect;
19
+
16
20
  export function useEffectEvent<T extends Function>(fn?: T): T {
17
21
  const ref = useRef<T | null | undefined>(null);
18
- useLayoutEffect(() => {
22
+ useEarlyEffect(() => {
19
23
  ref.current = fn;
20
24
  }, [fn]);
21
25
  // @ts-ignore
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import {RefObject} from '@react-types/shared';
14
- import {useEffect, useRef} from 'react';
14
+ import {useEffect} from 'react';
15
15
  import {useEffectEvent} from './useEffectEvent';
16
16
 
17
17
  export function useFormReset<T>(
@@ -19,15 +19,15 @@ export function useFormReset<T>(
19
19
  initialValue: T,
20
20
  onReset: (value: T) => void
21
21
  ): void {
22
- let resetValue = useRef(initialValue);
23
22
  let handleReset = useEffectEvent(() => {
24
23
  if (onReset) {
25
- onReset(resetValue.current);
24
+ onReset(initialValue);
26
25
  }
27
26
  });
28
27
 
29
28
  useEffect(() => {
30
29
  let form = ref?.current?.form;
30
+
31
31
  form?.addEventListener('reset', handleReset);
32
32
  return () => {
33
33
  form?.removeEventListener('reset', handleReset);
@@ -15,6 +15,6 @@ import React from 'react';
15
15
  // During SSR, React emits a warning when calling useLayoutEffect.
16
16
  // Since neither useLayoutEffect nor useEffect run on the server,
17
17
  // we can suppress this by replace it with a noop on the server.
18
- export const useLayoutEffect = typeof document !== 'undefined'
18
+ export const useLayoutEffect: typeof React.useLayoutEffect = typeof document !== 'undefined'
19
19
  ? React.useLayoutEffect
20
20
  : () => {};