diff --git a/package.json b/package.json index aa6d9caff5..689c7b7b4e 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^29.0.1", "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-unused-imports": "^4.1.4", "husky": "9.1.7", "jest": "^30.0.5", diff --git a/src/click_outside_wrapper.tsx b/src/click_outside_wrapper.tsx index b9ea78375f..7b7b68e89f 100644 --- a/src/click_outside_wrapper.tsx +++ b/src/click_outside_wrapper.tsx @@ -17,7 +17,9 @@ const useDetectClickOutside = ( ) => { const ref = useRef(null); const onClickOutsideRef = useRef(onClickOutside); - onClickOutsideRef.current = onClickOutside; + useEffect(() => { + onClickOutsideRef.current = onClickOutside; + }, [onClickOutside]); const handleClickOutside = useCallback( (event: MouseEvent) => { const target = diff --git a/src/popper_component.tsx b/src/popper_component.tsx index dafcdd46d5..7020981ac6 100644 --- a/src/popper_component.tsx +++ b/src/popper_component.tsx @@ -50,6 +50,7 @@ export const PopperComponent: React.FC = (props) => { const classes = clsx("react-datepicker-popper", className); popper = ( + {/* eslint-disable react-hooks/refs -- Floating UI values are designed to be used during render */}
= (props) => { /> )}
+ {/* eslint-enable react-hooks/refs */}
); } @@ -91,6 +93,7 @@ export const PopperComponent: React.FC = (props) => { return ( <> + {/* eslint-disable-next-line react-hooks/refs -- Floating UI refs are designed to be used during render */}
{targetComponent}
diff --git a/src/test/helper_components/shadow_root.tsx b/src/test/helper_components/shadow_root.tsx index 475f039897..098d9bb0f6 100644 --- a/src/test/helper_components/shadow_root.tsx +++ b/src/test/helper_components/shadow_root.tsx @@ -5,29 +5,31 @@ import React, { useRef, useState, } from "react"; -import { createPortal } from "react-dom"; +import { createPortal, flushSync } from "react-dom"; const ShadowRoot: FC = ({ children }) => { + const [shadowRoot, setShadowRoot] = useState(null); + const containerRef = useRef(null); - const shadowRootRef = useRef(null); - const [isInitialized, setIsInitialized] = useState(false); + const isInitializedRef = useRef(false); useLayoutEffect(() => { const container = containerRef.current; - if (isInitialized || !container) { + if (isInitializedRef.current || !container) { return; } - shadowRootRef.current = + const root = container.shadowRoot ?? container.attachShadow({ mode: "open" }); - setIsInitialized(true); - }, [isInitialized]); + isInitializedRef.current = true; + // Use flushSync to synchronously update state within effect, avoiding cascading renders + // while ensuring the shadow root is available immediately for tests + flushSync(() => setShadowRoot(root)); + }, []); return (
- {isInitialized && - shadowRootRef.current && - createPortal(children, shadowRootRef.current)} + {shadowRoot && createPortal(children, shadowRoot)}
); }; diff --git a/src/with_floating.tsx b/src/with_floating.tsx index f860a1a165..0f4044f0ae 100644 --- a/src/with_floating.tsx +++ b/src/with_floating.tsx @@ -56,6 +56,7 @@ export default function withFloating( middleware: [ flip({ padding: 15 }), offset(10), + // eslint-disable-next-line react-hooks/refs -- Floating UI requires refs to be passed during render arrow({ element: arrowRef }), ...(props.popperModifiers ?? []), ], diff --git a/yarn.lock b/yarn.lock index 13d355d5f4..bd1fc10b70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -77,6 +77,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.24.4": + version: 7.28.5 + resolution: "@babel/core@npm:7.28.5" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.5" + "@babel/helper-compilation-targets": "npm:^7.27.2" + "@babel/helper-module-transforms": "npm:^7.28.3" + "@babel/helpers": "npm:^7.28.4" + "@babel/parser": "npm:^7.28.5" + "@babel/template": "npm:^7.27.2" + "@babel/traverse": "npm:^7.28.5" + "@babel/types": "npm:^7.28.5" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/535f82238027621da6bdffbdbe896ebad3558b311d6f8abc680637a9859b96edbf929ab010757055381570b29cf66c4a295b5618318d27a4273c0e2033925e72 + languageName: node + linkType: hard + "@babel/eslint-parser@npm:^7.26.5": version: 7.28.4 resolution: "@babel/eslint-parser@npm:7.28.4" @@ -130,6 +153,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/generator@npm:7.28.5" + dependencies: + "@babel/parser": "npm:^7.28.5" + "@babel/types": "npm:^7.28.5" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/9f219fe1d5431b6919f1a5c60db8d5d34fe546c0d8f5a8511b32f847569234ffc8032beb9e7404649a143f54e15224ecb53a3d11b6bb85c3203e573d91fca752 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" @@ -454,6 +490,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-validator-identifier@npm:7.28.5" + checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847 + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-validator-option@npm:7.27.1" @@ -493,6 +536,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.4, @babel/parser@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/parser@npm:7.28.5" + dependencies: + "@babel/types": "npm:^7.28.5" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/5bbe48bf2c79594ac02b490a41ffde7ef5aa22a9a88ad6bcc78432a6ba8a9d638d531d868bd1f104633f1f6bba9905746e15185b8276a3756c42b765d131b1ef + languageName: node + linkType: hard + "@babel/parser@npm:^7.27.1, @babel/parser@npm:^7.27.2": version: 7.27.2 resolution: "@babel/parser@npm:7.27.2" @@ -1718,6 +1772,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/traverse@npm:7.28.5" + dependencies: + "@babel/code-frame": "npm:^7.27.1" + "@babel/generator": "npm:^7.28.5" + "@babel/helper-globals": "npm:^7.28.0" + "@babel/parser": "npm:^7.28.5" + "@babel/template": "npm:^7.27.2" + "@babel/types": "npm:^7.28.5" + debug: "npm:^4.3.1" + checksum: 10c0/f6c4a595993ae2b73f2d4cd9c062f2e232174d293edd4abe1d715bd6281da8d99e47c65857e8d0917d9384c65972f4acdebc6749a7c40a8fcc38b3c7fb3e706f + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.3, @babel/types@npm:^7.4.4": version: 7.26.3 resolution: "@babel/types@npm:7.26.3" @@ -1768,6 +1837,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/types@npm:7.28.5" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.28.5" + checksum: 10c0/a5a483d2100befbf125793640dec26b90b95fd233a94c19573325898a5ce1e52cdfa96e495c7dcc31b5eca5b66ce3e6d4a0f5a4a62daec271455959f208ab08a + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -5883,12 +5962,18 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^5.1.0": - version: 5.2.0 - resolution: "eslint-plugin-react-hooks@npm:5.2.0" +"eslint-plugin-react-hooks@npm:^7.0.1": + version: 7.0.1 + resolution: "eslint-plugin-react-hooks@npm:7.0.1" + dependencies: + "@babel/core": "npm:^7.24.4" + "@babel/parser": "npm:^7.24.4" + hermes-parser: "npm:^0.25.1" + zod: "npm:^3.25.0 || ^4.0.0" + zod-validation-error: "npm:^3.5.0 || ^4.0.0" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - checksum: 10c0/1c8d50fa5984c6dea32470651807d2922cc3934cf3425e78f84a24c2dfd972e7f019bee84aefb27e0cf2c13fea0ac1d4473267727408feeb1c56333ca1489385 + checksum: 10c0/1e711d1a9d1fa9cfc51fa1572500656577201199c70c795c6a27adfc1df39e5c598f69aab6aa91117753d23cc1f11388579a2bed14921cf9a4efe60ae8618496 languageName: node linkType: hard @@ -6795,6 +6880,22 @@ __metadata: languageName: node linkType: hard +"hermes-estree@npm:0.25.1": + version: 0.25.1 + resolution: "hermes-estree@npm:0.25.1" + checksum: 10c0/48be3b2fa37a0cbc77a112a89096fa212f25d06de92781b163d67853d210a8a5c3784fac23d7d48335058f7ed283115c87b4332c2a2abaaccc76d0ead1a282ac + languageName: node + linkType: hard + +"hermes-parser@npm:^0.25.1": + version: 0.25.1 + resolution: "hermes-parser@npm:0.25.1" + dependencies: + hermes-estree: "npm:0.25.1" + checksum: 10c0/3abaa4c6f1bcc25273f267297a89a4904963ea29af19b8e4f6eabe04f1c2c7e9abd7bfc4730ddb1d58f2ea04b6fee74053d8bddb5656ec6ebf6c79cc8d14202c + languageName: node + linkType: hard + "hookified@npm:^1.11.0": version: 1.12.0 resolution: "hookified@npm:1.12.0" @@ -9710,7 +9811,7 @@ __metadata: eslint-plugin-import: "npm:^2.31.0" eslint-plugin-jest: "npm:^29.0.1" eslint-plugin-react: "npm:^7.37.4" - eslint-plugin-react-hooks: "npm:^5.1.0" + eslint-plugin-react-hooks: "npm:^7.0.1" eslint-plugin-unused-imports: "npm:^4.1.4" husky: "npm:9.1.7" jest: "npm:^30.0.5" @@ -11960,3 +12061,19 @@ __metadata: checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f languageName: node linkType: hard + +"zod-validation-error@npm:^3.5.0 || ^4.0.0": + version: 4.0.2 + resolution: "zod-validation-error@npm:4.0.2" + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + checksum: 10c0/0ccfec48c46de1be440b719cd02044d4abb89ed0e14c13e637cd55bf29102f67ccdba373f25def0fc7130e5f15025be4d557a7edcc95d5a3811599aade689e1b + languageName: node + linkType: hard + +"zod@npm:^3.25.0 || ^4.0.0": + version: 4.1.12 + resolution: "zod@npm:4.1.12" + checksum: 10c0/b64c1feb19e99d77075261eaf613e0b2be4dfcd3551eff65ad8b4f2a079b61e379854d066f7d447491fcf193f45babd8095551a9d47973d30b46b6d8e2c46774 + languageName: node + linkType: hard