From 0b56eb078ae1314d85d4dcd56a4d3e40b71a288a Mon Sep 17 00:00:00 2001 From: pataar Date: Sat, 11 Oct 2025 23:12:15 +0200 Subject: [PATCH 1/5] Add the React Compiler --- eslint.config.js | 10 +- package-lock.json | 205 +++++++++++------- package.json | 13 +- .../js/components/two-factor-setup-modal.tsx | 15 +- resources/js/components/ui/sidebar.tsx | 18 +- resources/js/hooks/use-appearance.tsx | 2 + resources/js/hooks/use-mobile.tsx | 32 ++- resources/js/pages/welcome.tsx | 6 +- vite.config.ts | 6 +- 9 files changed, 178 insertions(+), 129 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 7c86a6ea..7a9fc2ce 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -8,6 +8,7 @@ import typescript from 'typescript-eslint'; /** @type {import('eslint').Linter.Config[]} */ export default [ js.configs.recommended, + reactHooks.configs.flat.recommended, ...typescript.configs.recommended, { ...react.configs.flat.recommended, @@ -28,15 +29,6 @@ export default [ }, }, }, - { - plugins: { - 'react-hooks': reactHooks, - }, - rules: { - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn', - }, - }, { ignores: ['vendor', 'node_modules', 'public', 'bootstrap/ssr', 'tailwind.config.js'], }, diff --git a/package-lock.json b/package-lock.json index b772934d..69488c36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,9 +21,9 @@ "@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.8", "@tailwindcss/vite": "^4.1.11", - "@types/react": "^19.0.3", - "@types/react-dom": "^19.0.2", - "@vitejs/plugin-react": "^4.6.0", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "@vitejs/plugin-react": "^5.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "concurrently": "^9.0.1", @@ -31,8 +31,8 @@ "input-otp": "^1.4.2", "laravel-vite-plugin": "^2.0", "lucide-react": "^0.475.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "tailwind-merge": "^3.0.1", "tailwindcss": "^4.0.0", "tailwindcss-animate": "^1.0.7", @@ -43,10 +43,11 @@ "@eslint/js": "^9.19.0", "@laravel/vite-plugin-wayfinder": "^0.1.3", "@types/node": "^22.13.5", + "babel-plugin-react-compiler": "^1.0.0", "eslint": "^9.17.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-react": "^7.37.3", - "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-hooks": "^7.0.0", "prettier": "^3.4.2", "prettier-plugin-organize-imports": "^4.1.0", "prettier-plugin-tailwindcss": "^0.6.11", @@ -58,18 +59,6 @@ "lightningcss-linux-x64-gnu": "^1.29.1" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -92,20 +81,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", - "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.3", - "@babel/parser": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -219,23 +209,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", - "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2" + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", - "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.28.2" + "@babel/types": "^7.28.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -286,16 +278,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", - "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.3", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2", + "@babel/types": "^7.28.4", "debug": "^4.3.1" }, "engines": { @@ -303,9 +296,10 @@ } }, "node_modules/@babel/types": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", - "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" @@ -2072,9 +2066,10 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==" + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", + "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.46.2", @@ -2721,19 +2716,21 @@ } }, "node_modules/@types/react": { - "version": "19.1.10", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz", - "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "license": "MIT", "dependencies": { "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "19.1.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", - "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz", + "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==", + "license": "MIT", "peerDependencies": { - "@types/react": "^19.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -2994,19 +2991,20 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", + "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", + "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", + "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", + "@rolldown/pluginutils": "1.0.0-beta.38", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" @@ -3258,6 +3256,16 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4045,12 +4053,20 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.0.tgz", + "integrity": "sha512-fNXaOwvKwq2+pXiRpXc825Vd63+KM4DLL40Rtlycb8m7fYpp6efrTp1sa6ZbP/Ap58K2bEKFXRmhURE+CJAQWw==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.22.4 || ^4.0.0", + "zod-validation-error": "^3.0.3 || ^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" @@ -4576,6 +4592,23 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -6005,22 +6038,24 @@ ] }, "node_modules/react": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", - "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", - "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.1.1" + "react": "^19.2.0" } }, "node_modules/react-is": { @@ -6323,9 +6358,10 @@ } }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==" + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", @@ -7310,6 +7346,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/package.json b/package.json index e186f692..06842c46 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,11 @@ "@eslint/js": "^9.19.0", "@laravel/vite-plugin-wayfinder": "^0.1.3", "@types/node": "^22.13.5", + "babel-plugin-react-compiler": "^1.0.0", "eslint": "^9.17.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-react": "^7.37.3", - "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-hooks": "^7.0.0", "prettier": "^3.4.2", "prettier-plugin-organize-imports": "^4.1.0", "prettier-plugin-tailwindcss": "^0.6.11", @@ -40,9 +41,9 @@ "@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.8", "@tailwindcss/vite": "^4.1.11", - "@types/react": "^19.0.3", - "@types/react-dom": "^19.0.2", - "@vitejs/plugin-react": "^4.6.0", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "@vitejs/plugin-react": "^5.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "concurrently": "^9.0.1", @@ -50,8 +51,8 @@ "input-otp": "^1.4.2", "laravel-vite-plugin": "^2.0", "lucide-react": "^0.475.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "tailwind-merge": "^3.0.1", "tailwindcss": "^4.0.0", "tailwindcss-animate": "^1.0.7", diff --git a/resources/js/components/two-factor-setup-modal.tsx b/resources/js/components/two-factor-setup-modal.tsx index 317149ea..434750e2 100644 --- a/resources/js/components/two-factor-setup-modal.tsx +++ b/resources/js/components/two-factor-setup-modal.tsx @@ -294,19 +294,18 @@ export default function TwoFactorSetupModal({ }, [twoFactorEnabled, clearSetupData]); useEffect(() => { - if (!isOpen) { - resetModalState(); - - return; - } - - if (!qrCodeSvg) { + if (isOpen && !qrCodeSvg) { fetchSetupData(); } }, [isOpen, qrCodeSvg, fetchSetupData, resetModalState]); + const handleClose = useCallback(() => { + resetModalState(); + onClose(); + }, [onClose, resetModalState]); + return ( - !open && onClose()}> + !open && handleClose()}> diff --git a/resources/js/components/ui/sidebar.tsx b/resources/js/components/ui/sidebar.tsx index ac6bd635..95aee212 100644 --- a/resources/js/components/ui/sidebar.tsx +++ b/resources/js/components/ui/sidebar.tsx @@ -601,10 +601,14 @@ function SidebarMenuSkeleton({ }: React.ComponentProps<"div"> & { showIcon?: boolean }) { - // Random width between 50 to 90%. - const width = React.useMemo(() => { - return `${Math.floor(Math.random() * 40) + 50}%` - }, []) + + // wrapping in useState to ensure the width is stable across renders + // also ensures we have a stable reference to the style object + const [skeletonStyle] = React.useState(() => ( + { + "--skeleton-width": `${Math.floor(Math.random() * 40) + 50}%` // Random width between 50 to 90%. + } as React.CSSProperties + )) return (
) diff --git a/resources/js/hooks/use-appearance.tsx b/resources/js/hooks/use-appearance.tsx index 56f5bcc5..2c6b5682 100644 --- a/resources/js/hooks/use-appearance.tsx +++ b/resources/js/hooks/use-appearance.tsx @@ -69,6 +69,8 @@ export function useAppearance() { const savedAppearance = localStorage.getItem( 'appearance', ) as Appearance | null; + + // eslint-disable-next-line react-hooks/set-state-in-effect updateAppearance(savedAppearance || 'system'); return () => diff --git a/resources/js/hooks/use-mobile.tsx b/resources/js/hooks/use-mobile.tsx index e40d5d98..57dd3592 100644 --- a/resources/js/hooks/use-mobile.tsx +++ b/resources/js/hooks/use-mobile.tsx @@ -1,24 +1,20 @@ -import { useEffect, useState } from 'react'; +import { useSyncExternalStore } from 'react'; const MOBILE_BREAKPOINT = 768; -export function useIsMobile() { - const [isMobile, setIsMobile] = useState(); - - useEffect(() => { - const mql = window.matchMedia( - `(max-width: ${MOBILE_BREAKPOINT - 1}px)`, - ); - - const onChange = () => { - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); - }; +const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); - mql.addEventListener('change', onChange); - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); - - return () => mql.removeEventListener('change', onChange); - }, []); +function mediaQueryListener(callback: (event: MediaQueryListEvent) => void) { + mql.addEventListener('change', callback); + return () => { + mql.removeEventListener('change', callback); + }; +} - return !!isMobile; +export function useIsMobile() { + return useSyncExternalStore( + mediaQueryListener, // React won't resubscribe for as long as you pass the same function + () => window.innerWidth < MOBILE_BREAKPOINT, // How to get the value on the client + () => false, // How to get the value on the server + ); } diff --git a/resources/js/pages/welcome.tsx b/resources/js/pages/welcome.tsx index 8fdc789d..dbc6f31f 100644 --- a/resources/js/pages/welcome.tsx +++ b/resources/js/pages/welcome.tsx @@ -232,11 +232,7 @@ export default function Welcome() { strokeWidth={1} /> - + Date: Mon, 13 Oct 2025 13:45:18 -0400 Subject: [PATCH 2/5] Update two-factor-setup-modal.tsx --- resources/js/components/two-factor-setup-modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/components/two-factor-setup-modal.tsx b/resources/js/components/two-factor-setup-modal.tsx index 434750e2..c67da314 100644 --- a/resources/js/components/two-factor-setup-modal.tsx +++ b/resources/js/components/two-factor-setup-modal.tsx @@ -278,7 +278,6 @@ export default function TwoFactorSetupModal({ const handleModalNextStep = useCallback(() => { if (requiresConfirmation) { setShowVerificationStep(true); - return; } @@ -288,6 +287,7 @@ export default function TwoFactorSetupModal({ const resetModalState = useCallback(() => { setShowVerificationStep(false); + if (twoFactorEnabled) { clearSetupData(); } @@ -297,7 +297,7 @@ export default function TwoFactorSetupModal({ if (isOpen && !qrCodeSvg) { fetchSetupData(); } - }, [isOpen, qrCodeSvg, fetchSetupData, resetModalState]); + }, [isOpen, qrCodeSvg, fetchSetupData]); const handleClose = useCallback(() => { resetModalState(); From 33d301a4f8d9dc70bf1f45eedfa64eb15e55fd03 Mon Sep 17 00:00:00 2001 From: Joe Tannenbaum Date: Mon, 13 Oct 2025 13:52:29 -0400 Subject: [PATCH 3/5] Update use-mobile.tsx --- resources/js/hooks/use-mobile.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/js/hooks/use-mobile.tsx b/resources/js/hooks/use-mobile.tsx index 57dd3592..f65eb142 100644 --- a/resources/js/hooks/use-mobile.tsx +++ b/resources/js/hooks/use-mobile.tsx @@ -6,6 +6,7 @@ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); function mediaQueryListener(callback: (event: MediaQueryListEvent) => void) { mql.addEventListener('change', callback); + return () => { mql.removeEventListener('change', callback); }; @@ -13,8 +14,7 @@ function mediaQueryListener(callback: (event: MediaQueryListEvent) => void) { export function useIsMobile() { return useSyncExternalStore( - mediaQueryListener, // React won't resubscribe for as long as you pass the same function - () => window.innerWidth < MOBILE_BREAKPOINT, // How to get the value on the client - () => false, // How to get the value on the server + mediaQueryListener, + () => window.innerWidth < MOBILE_BREAKPOINT, ); } From 7732c0ca9122a494f85c794e53ee30cafbd6e23a Mon Sep 17 00:00:00 2001 From: Pieter Willekens Date: Mon, 13 Oct 2025 19:47:48 +0000 Subject: [PATCH 4/5] move snapshot function from component --- resources/js/hooks/use-mobile.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/js/hooks/use-mobile.tsx b/resources/js/hooks/use-mobile.tsx index f65eb142..067b96e2 100644 --- a/resources/js/hooks/use-mobile.tsx +++ b/resources/js/hooks/use-mobile.tsx @@ -12,9 +12,10 @@ function mediaQueryListener(callback: (event: MediaQueryListEvent) => void) { }; } +function isSmallerThanBreakpoint() { + return window.innerWidth < MOBILE_BREAKPOINT; +} + export function useIsMobile() { - return useSyncExternalStore( - mediaQueryListener, - () => window.innerWidth < MOBILE_BREAKPOINT, - ); + return useSyncExternalStore(mediaQueryListener, isSmallerThanBreakpoint); } From 3e36a19f0fe053629f4ca2bfb5fd3ddfd70bcdec Mon Sep 17 00:00:00 2001 From: Joe Tannenbaum Date: Mon, 20 Oct 2025 12:58:33 -0400 Subject: [PATCH 5/5] Update use-mobile.tsx --- resources/js/hooks/use-mobile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/hooks/use-mobile.tsx b/resources/js/hooks/use-mobile.tsx index 067b96e2..710ad6e1 100644 --- a/resources/js/hooks/use-mobile.tsx +++ b/resources/js/hooks/use-mobile.tsx @@ -13,7 +13,7 @@ function mediaQueryListener(callback: (event: MediaQueryListEvent) => void) { } function isSmallerThanBreakpoint() { - return window.innerWidth < MOBILE_BREAKPOINT; + return mql.matches; } export function useIsMobile() {