From bcdea334e7aee55282f8cd8b04919f1970b71012 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Wed, 2 Apr 2025 08:38:25 -0400 Subject: [PATCH 1/7] #106 update deps --- package-lock.json | 168 +++++++++++++++++++++++----------------------- package.json | 10 +-- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed9ef00..c3b15af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,9 +16,9 @@ "@fortawesome/react-fontawesome": "0.2.2", "@hookform/resolvers": "4.1.3", "@react-spring/web": "9.7.5", - "@tailwindcss/vite": "4.0.17", - "@tanstack/react-query": "5.71.1", - "@tanstack/react-query-devtools": "5.71.1", + "@tailwindcss/vite": "4.1.1", + "@tanstack/react-query": "5.71.3", + "@tanstack/react-query-devtools": "5.71.3", "@tanstack/react-table": "8.21.2", "axios": "1.8.4", "class-variance-authority": "0.7.1", @@ -34,8 +34,8 @@ "react-i18next": "15.4.1", "react-router-dom": "7.4.1", "recharts": "2.15.1", - "tailwind-merge": "3.0.2", - "tailwindcss": "4.0.17", + "tailwind-merge": "3.1.0", + "tailwindcss": "4.1.1", "uuid": "11.1.0", "yup": "1.6.1" }, @@ -2941,42 +2941,43 @@ } }, "node_modules/@tailwindcss/node": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.17.tgz", - "integrity": "sha512-LIdNwcqyY7578VpofXyqjH6f+3fP4nrz7FBLki5HpzqjYfXdF2m/eW18ZfoKePtDGg90Bvvfpov9d2gy5XVCbg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.1.tgz", + "integrity": "sha512-xvlh4pvfG/bkv0fEtJDABAm1tjtSmSyi2QmS4zyj1EKNI1UiOYiUq1IphSwDsNJ5vJ9cWEGs4rJXpUdCN2kujQ==", "license": "MIT", "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", - "tailwindcss": "4.0.17" + "lightningcss": "1.29.2", + "tailwindcss": "4.1.1" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.17.tgz", - "integrity": "sha512-B4OaUIRD2uVrULpAD1Yksx2+wNarQr2rQh65nXqaqbLY1jCd8fO+3KLh/+TH4Hzh2NTHQvgxVbPdUDOtLk7vAw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.1.tgz", + "integrity": "sha512-7+YBgnPQ4+jv6B6WVOerJ6WOzDzNJXrRKDts674v6TKAqFqYRr9+EBtSziO7nNcwQ8JtoZNMeqA+WJDjtCM/7w==", "license": "MIT", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.0.17", - "@tailwindcss/oxide-darwin-arm64": "4.0.17", - "@tailwindcss/oxide-darwin-x64": "4.0.17", - "@tailwindcss/oxide-freebsd-x64": "4.0.17", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.17", - "@tailwindcss/oxide-linux-arm64-gnu": "4.0.17", - "@tailwindcss/oxide-linux-arm64-musl": "4.0.17", - "@tailwindcss/oxide-linux-x64-gnu": "4.0.17", - "@tailwindcss/oxide-linux-x64-musl": "4.0.17", - "@tailwindcss/oxide-win32-arm64-msvc": "4.0.17", - "@tailwindcss/oxide-win32-x64-msvc": "4.0.17" + "@tailwindcss/oxide-android-arm64": "4.1.1", + "@tailwindcss/oxide-darwin-arm64": "4.1.1", + "@tailwindcss/oxide-darwin-x64": "4.1.1", + "@tailwindcss/oxide-freebsd-x64": "4.1.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.1", + "@tailwindcss/oxide-linux-x64-musl": "4.1.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.1" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.17.tgz", - "integrity": "sha512-3RfO0ZK64WAhop+EbHeyxGThyDr/fYhxPzDbEQjD2+v7ZhKTb2svTWy+KK+J1PHATus2/CQGAGp7pHY/8M8ugg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.1.tgz", + "integrity": "sha512-gTyRzfdParpoCU1yyUC/iN6XK6T0Ra4bDlF8Aeul5NP9cLzKEZDogdNVNGv5WZmCDkVol7qlex7TMmcfytMmmw==", "cpu": [ "arm64" ], @@ -2990,9 +2991,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.17.tgz", - "integrity": "sha512-e1uayxFQCCDuzTk9s8q7MC5jFN42IY7nzcr5n0Mw/AcUHwD6JaBkXnATkD924ZsHyPDvddnusIEvkgLd2CiREg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.1.tgz", + "integrity": "sha512-dI0QbdMWBvLB3MtaTKetzUKG9CUUQow8JSP4Nm+OxVokeZ+N+f1OmZW/hW1LzMxpx9RQCBgSRL+IIvKRat5Wdg==", "cpu": [ "arm64" ], @@ -3006,9 +3007,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.17.tgz", - "integrity": "sha512-d6z7HSdOKfXQ0HPlVx1jduUf/YtBuCCtEDIEFeBCzgRRtDsUuRtofPqxIVaSCUTOk5+OfRLonje6n9dF6AH8wQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.1.tgz", + "integrity": "sha512-2Y+NPQOTRBCItshPgY/CWg4bKi7E9evMg4bgdb6h9iZObCZLOe3doPcuSxGS3DB0dKyMFKE8pTdWtFUbxZBMSA==", "cpu": [ "x64" ], @@ -3022,9 +3023,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.17.tgz", - "integrity": "sha512-EjrVa6lx3wzXz3l5MsdOGtYIsRjgs5Mru6lDv4RuiXpguWeOb3UzGJ7vw7PEzcFadKNvNslEQqoAABeMezprxQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.1.tgz", + "integrity": "sha512-N97NGMsB/7CHShbc5ube4dcsW/bYENkBrg8yWi8ieN9boYVRdw3cZviVryV/Nfu9bKbBV9kUvduFF2qBI7rEqg==", "cpu": [ "x64" ], @@ -3038,9 +3039,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.17.tgz", - "integrity": "sha512-65zXfCOdi8wuaY0Ye6qMR5LAXokHYtrGvo9t/NmxvSZtCCitXV/gzJ/WP5ksXPhff1SV5rov0S+ZIZU+/4eyCQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.1.tgz", + "integrity": "sha512-33Lk6KbHnUZbXqza6RWNFo9wqPQ4+H5BAn1CkUUfC1RZ1vYbyDN6+iJPj53wmnWJ3mhRI8jWt3Jt1fO02IVdUQ==", "cpu": [ "arm" ], @@ -3054,9 +3055,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.17.tgz", - "integrity": "sha512-+aaq6hJ8ioTdbJV5IA1WjWgLmun4T7eYLTvJIToiXLHy5JzUERRbIZjAcjgK9qXMwnvuu7rqpxzej+hGoEcG5g==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.1.tgz", + "integrity": "sha512-LyW35RzSUy+80WYScv03HKasAUmMFDaSbNpWfk1gG5gEE9kuRGnDzSrqMoLAmY/kzMCYP/1kqmUiAx8EFLkI2A==", "cpu": [ "arm64" ], @@ -3070,9 +3071,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.17.tgz", - "integrity": "sha512-/FhWgZCdUGAeYHYnZKekiOC0aXFiBIoNCA0bwzkICiMYS5Rtx2KxFfMUXQVnl4uZRblG5ypt5vpPhVaXgGk80w==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.1.tgz", + "integrity": "sha512-1KPnDMlHdqjPTUSFjx55pafvs8RZXRgxfeRgUrukwDKkuj7gFk28vW3Mx65YdiugAc9NWs3VgueZWaM1Po6uGw==", "cpu": [ "arm64" ], @@ -3086,9 +3087,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.17.tgz", - "integrity": "sha512-gELJzOHK6GDoIpm/539Golvk+QWZjxQcbkKq9eB2kzNkOvrP0xc5UPgO9bIMNt1M48mO8ZeNenCMGt6tfkvVBg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.1.tgz", + "integrity": "sha512-4WdzA+MRlsinEEE6yxNMLJxpw0kE9XVipbAKdTL8BeUpyC2TdA3TL46lBulXzKp3BIxh3nqyR/UCqzl5o+3waQ==", "cpu": [ "x64" ], @@ -3102,9 +3103,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.17.tgz", - "integrity": "sha512-68NwxcJrZn94IOW4TysMIbYv5AlM6So1luTlbYUDIGnKma1yTFGBRNEJ+SacJ3PZE2rgcTBNRHX1TB4EQ/XEHw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.1.tgz", + "integrity": "sha512-q7Ugbw3ARcjCW2VMUYrcMbJ6aMQuWPArBBE2EqC/swPZTdGADvMQSlvR0VKusUM4HoSsO7ZbvcZ53YwR57+AKw==", "cpu": [ "x64" ], @@ -3118,9 +3119,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.17.tgz", - "integrity": "sha512-AkBO8efP2/7wkEXkNlXzRD4f/7WerqKHlc6PWb5v0jGbbm22DFBLbIM19IJQ3b+tNewQZa+WnPOaGm0SmwMNjw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.1.tgz", + "integrity": "sha512-0KpqsovgHcIzm7eAGzzEZsEs0/nPYXnRBv+aPq/GehpNQuE/NAQu+YgZXIIof+VflDFuyXOEnaFr7T5MZ1INhA==", "cpu": [ "arm64" ], @@ -3134,9 +3135,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.17.tgz", - "integrity": "sha512-7/DTEvXcoWlqX0dAlcN0zlmcEu9xSermuo7VNGX9tJ3nYMdo735SHvbrHDln1+LYfF6NhJ3hjbpbjkMOAGmkDg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.1.tgz", + "integrity": "sha512-B1mjeXNS26kBOHv5sXARf6Wd0PWHV9x1TDlW0ummrBUOUAxAy5wcy4Nii1wzNvCdvC448hgiL06ylhwAbNthmg==", "cpu": [ "x64" ], @@ -3150,24 +3151,23 @@ } }, "node_modules/@tailwindcss/vite": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.17.tgz", - "integrity": "sha512-HJbBYDlDVg5cvYZzECb6xwc1IDCEM3uJi3hEZp3BjZGCNGJcTsnCpan+z+VMW0zo6gR0U6O6ElqU1OoZ74Dhww==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.1.tgz", + "integrity": "sha512-tFTkRZwXq4XKr3S2dUZBxy80wbWYHdDSsu4QOB1yE1HJFKjfxKVpXtup4dyTVdQcLInoHC9lZXFPHnjoBP774g==", "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.0.17", - "@tailwindcss/oxide": "4.0.17", - "lightningcss": "1.29.2", - "tailwindcss": "4.0.17" + "@tailwindcss/node": "4.1.1", + "@tailwindcss/oxide": "4.1.1", + "tailwindcss": "4.1.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "node_modules/@tanstack/query-core": { - "version": "5.71.1", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.71.1.tgz", - "integrity": "sha512-4+ZswCHOfJX+ikhXNoocamTUmJcHtB+Ljjz/oJkC7/eKB5IrzEwR4vEwZUENiPi+wISucJHR5TUbuuJ26w3kdQ==", + "version": "5.71.3", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.71.3.tgz", + "integrity": "sha512-SW7PXYpKiQCZU5pPOXG2UiHX1oSAxLyxoJiYbQ3aLYiABJW0UnfBZ9PVnO/x4ZCIVK30wfDn0h6Mrsr10q922Q==", "license": "MIT", "funding": { "type": "github", @@ -3175,9 +3175,9 @@ } }, "node_modules/@tanstack/query-devtools": { - "version": "5.67.2", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.67.2.tgz", - "integrity": "sha512-O4QXFFd7xqp6EX7sdvc9tsVO8nm4lpWBqwpgjpVLW5g7IeOY6VnS/xvs/YzbRhBVkKTMaJMOUGU7NhSX+YGoNg==", + "version": "5.71.3", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.71.3.tgz", + "integrity": "sha512-+m706O9Rly+34z0JNkRiGMVKEF5vMvViGoj7DNkYMZ7AiGq6EHDfg7zdjPv3srixHYjkdHlcsO72oyh+GtyrlQ==", "license": "MIT", "funding": { "type": "github", @@ -3185,12 +3185,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.71.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.71.1.tgz", - "integrity": "sha512-6BTkaSIGT58MroI4kIGXNdx/NhirXPU+75AJObLq+WBa39WmoxhzSk0YX+hqWJ/bvqZJFxslbEU4qIHaRZq+8Q==", + "version": "5.71.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.71.3.tgz", + "integrity": "sha512-4GZxKqiMX+CH4CxXiUBNipbqzk2V5jUU8Z4d6J+lSDu8OejcLtjx1hEDJzabFZHwd+ZHCsYLAJmM54kCS1/ekA==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.71.1" + "@tanstack/query-core": "5.71.3" }, "funding": { "type": "github", @@ -3201,19 +3201,19 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.71.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.71.1.tgz", - "integrity": "sha512-nETCStlMy1h3Hcy1rnHJVbW8ERsAErAzpCsBHIVd9AOjQgQjzjFl2FetlEZjRc+vMJjpJde9NDsftYhy7UA83A==", + "version": "5.71.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.71.3.tgz", + "integrity": "sha512-vA0h92TXbfKpk8p2mRbGt/bffJF7Fp8cJGArubge0Uyyh1FPzjgkFsWnkBz0IUThb9P8JU7eOftDwluv//zpAg==", "license": "MIT", "dependencies": { - "@tanstack/query-devtools": "5.67.2" + "@tanstack/query-devtools": "5.71.3" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.71.1", + "@tanstack/react-query": "^5.71.3", "react": "^18 || ^19" } }, @@ -8816,9 +8816,9 @@ "license": "MIT" }, "node_modules/tailwind-merge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.0.2.tgz", - "integrity": "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.1.0.tgz", + "integrity": "sha512-aV27Oj8B7U/tAOMhJsSGdWqelfmudnGMdXIlMnk1JfsjwSjts6o8HyfN7SFH3EztzH4YH8kk6GbLTHzITJO39Q==", "license": "MIT", "funding": { "type": "github", @@ -8826,9 +8826,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.17.tgz", - "integrity": "sha512-OErSiGzRa6rLiOvaipsDZvLMSpsBZ4ysB4f0VKGXUrjw2jfkJRd6kjRKV2+ZmTCNvwtvgdDam5D7w6WXsdLJZw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.1.tgz", + "integrity": "sha512-QNbdmeS979Efzim2g/bEvfuh+fTcIdp1y7gA+sb6OYSW74rt7Cr7M78AKdf6HqWT3d5AiTb7SwTT3sLQxr4/qw==", "license": "MIT" }, "node_modules/tapable": { diff --git a/package.json b/package.json index 1fbb19f..f06e846 100644 --- a/package.json +++ b/package.json @@ -32,9 +32,9 @@ "@fortawesome/react-fontawesome": "0.2.2", "@hookform/resolvers": "4.1.3", "@react-spring/web": "9.7.5", - "@tailwindcss/vite": "4.0.17", - "@tanstack/react-query": "5.71.1", - "@tanstack/react-query-devtools": "5.71.1", + "@tailwindcss/vite": "4.1.1", + "@tanstack/react-query": "5.71.3", + "@tanstack/react-query-devtools": "5.71.3", "@tanstack/react-table": "8.21.2", "axios": "1.8.4", "class-variance-authority": "0.7.1", @@ -50,8 +50,8 @@ "react-i18next": "15.4.1", "react-router-dom": "7.4.1", "recharts": "2.15.1", - "tailwind-merge": "3.0.2", - "tailwindcss": "4.0.17", + "tailwind-merge": "3.1.0", + "tailwindcss": "4.1.1", "uuid": "11.1.0", "yup": "1.6.1" }, From 0c36e9993441bdd93c6f84611652b924cd564d92 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Thu, 3 Apr 2025 15:12:52 -0400 Subject: [PATCH 2/7] #106 use zod instead of yup --- package-lock.json | 12 ++++++- package.json | 3 +- .../Form/__stories__/Input.stories.tsx | 12 +++---- .../Form/__stories__/Select.stories.tsx | 16 ++++----- .../Form/__stories__/Toggle.stories.tsx | 12 +++---- .../components/Form/__tests__/Input.test.tsx | 12 +++---- .../components/Form/__tests__/Select.test.tsx | 15 ++++---- .../Form/__tests__/Textarea.test.tsx | 13 ++++--- .../components/Form/__tests__/Toggle.test.tsx | 19 +++++----- src/common/providers/ConfigProvider.tsx | 35 +++++++++---------- .../Auth/Signin/components/SigninForm.tsx | 17 ++++----- .../Components/components/InputComponents.tsx | 18 +++++----- .../components/SelectComponents.tsx | 24 +++++++------ .../components/TextareaComponents.tsx | 20 ++++++----- .../components/ToggleComponents.tsx | 14 ++++---- src/pages/Tasks/components/Form/TaskForm.tsx | 19 +++++----- .../Form/__tests__/TaskForm.test.tsx | 10 ++++-- 17 files changed, 146 insertions(+), 125 deletions(-) diff --git a/package-lock.json b/package-lock.json index c3b15af..666be6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,8 @@ "tailwind-merge": "3.1.0", "tailwindcss": "4.1.1", "uuid": "11.1.0", - "yup": "1.6.1" + "yup": "1.6.1", + "zod": "3.24.2" }, "devDependencies": { "@chromatic-com/storybook": "3.2.6", @@ -9863,6 +9864,15 @@ "toposort": "^2.0.2", "type-fest": "^2.19.0" } + }, + "node_modules/zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index f06e846..844366d 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,8 @@ "tailwind-merge": "3.1.0", "tailwindcss": "4.1.1", "uuid": "11.1.0", - "yup": "1.6.1" + "yup": "1.6.1", + "zod": "3.24.2" }, "devDependencies": { "@chromatic-com/storybook": "3.2.6", diff --git a/src/common/components/Form/__stories__/Input.stories.tsx b/src/common/components/Form/__stories__/Input.stories.tsx index 4dfb816..bdc87d1 100644 --- a/src/common/components/Form/__stories__/Input.stories.tsx +++ b/src/common/components/Form/__stories__/Input.stories.tsx @@ -1,16 +1,16 @@ import type { Meta, StoryObj } from '@storybook/react'; import { useForm } from 'react-hook-form'; -import { InferType, object, string } from 'yup'; -import { yupResolver } from '@hookform/resolvers/yup'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { default as MyInput } from '../Input'; import { InputProps } from '../Input'; -const formSchema = object({ - color: string().required('Required'), +const formSchema = z.object({ + color: z.string().min(1, { message: 'Required' }), }); -type FormValues = InferType; +type FormValues = z.infer; /** * A wrapper for the `Input` component. Provides the RHF form `control` @@ -22,7 +22,7 @@ const Input = (props: Omit, 'control'>) => { color: '', }, mode: 'all', - resolver: yupResolver(formSchema), + resolver: zodResolver(formSchema), }); const onSubmit = () => {}; diff --git a/src/common/components/Form/__stories__/Select.stories.tsx b/src/common/components/Form/__stories__/Select.stories.tsx index 34d3311..96f986c 100644 --- a/src/common/components/Form/__stories__/Select.stories.tsx +++ b/src/common/components/Form/__stories__/Select.stories.tsx @@ -1,16 +1,16 @@ import type { Meta, StoryObj } from '@storybook/react'; import { useForm } from 'react-hook-form'; -import { InferType, object, string } from 'yup'; -import { yupResolver } from '@hookform/resolvers/yup'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { default as MySelect } from '../Select'; import { SelectProps } from '../Select'; -const formSchema = object({ - color: string().required('Required. ').oneOf(['blue', 'red'], 'Must be blue or red. '), +const formSchema = z.object({ + color: z.enum(['blue', 'red'], { message: 'Must be blue or red.' }), }); -type FormValues = InferType; +type FormValues = z.infer; /** * A wrapper for the `Select` component. Provides the RHF form `control` @@ -18,11 +18,9 @@ type FormValues = InferType; */ const Select = (props: Omit, 'control'>) => { const form = useForm({ - defaultValues: { - color: '', - }, + defaultValues: {}, mode: 'all', - resolver: yupResolver(formSchema), + resolver: zodResolver(formSchema), }); const onSubmit = () => {}; diff --git a/src/common/components/Form/__stories__/Toggle.stories.tsx b/src/common/components/Form/__stories__/Toggle.stories.tsx index 96879ec..b8c37a6 100644 --- a/src/common/components/Form/__stories__/Toggle.stories.tsx +++ b/src/common/components/Form/__stories__/Toggle.stories.tsx @@ -1,16 +1,16 @@ import type { Meta, StoryObj } from '@storybook/react'; import { useForm } from 'react-hook-form'; -import { boolean, InferType, object } from 'yup'; -import { yupResolver } from '@hookform/resolvers/yup'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { default as MyToggle } from '../Toggle'; import { ToggleProps } from '../Toggle'; -const formSchema = object({ - isEnabledNotifications: boolean(), +const formSchema = z.object({ + isEnabledNotifications: z.boolean(), }); -type FormValues = InferType; +type FormValues = z.infer; /** * A wrapper for the `Toggle` component. Provides the RHF form `control` @@ -22,7 +22,7 @@ const Toggle = (props: Omit, 'control'>) => { isEnabledNotifications: false, }, mode: 'all', - resolver: yupResolver(formSchema), + resolver: zodResolver(formSchema), }); const onSubmit = () => {}; diff --git a/src/common/components/Form/__tests__/Input.test.tsx b/src/common/components/Form/__tests__/Input.test.tsx index 154d63d..81c79cb 100644 --- a/src/common/components/Form/__tests__/Input.test.tsx +++ b/src/common/components/Form/__tests__/Input.test.tsx @@ -1,18 +1,18 @@ import { describe, expect, it } from 'vitest'; import userEvent from '@testing-library/user-event'; -import { InferType, object, string } from 'yup'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { render, screen } from 'test/test-utils'; import Input, { InputProps } from '../Input'; -const formSchema = object({ - color: string().required('Required'), +const formSchema = z.object({ + color: z.string().min(1, { message: 'Required' }), }); -type FormValues = InferType; +type FormValues = z.infer; /** * A wrapper for testing the `Input` component which requires some @@ -21,7 +21,7 @@ type FormValues = InferType; const InputWrapper = (props: Omit, 'control'>) => { const form = useForm({ defaultValues: { color: '' }, - resolver: yupResolver(formSchema), + resolver: zodResolver(formSchema), }); const onSubmit = () => {}; diff --git a/src/common/components/Form/__tests__/Select.test.tsx b/src/common/components/Form/__tests__/Select.test.tsx index 9e5e8d2..3c8ac90 100644 --- a/src/common/components/Form/__tests__/Select.test.tsx +++ b/src/common/components/Form/__tests__/Select.test.tsx @@ -1,18 +1,17 @@ import userEvent from '@testing-library/user-event'; import { describe, expect, it } from 'vitest'; import { useForm } from 'react-hook-form'; -import { InferType, object, string } from 'yup'; -import { yupResolver } from '@hookform/resolvers/yup'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { render, screen, waitFor } from 'test/test-utils'; import Select, { SelectProps } from '../Select'; -const formSchema = object({ - color: string().oneOf(['blue'], 'Must select a value in the list.'), +const formSchema = z.object({ + color: z.enum(['blue'], { message: 'Must select a value in the list.' }), }); - -type FormValues = InferType; +type FormValues = z.infer; /** * A wrapper for testing the `Select` component which requires some @@ -20,8 +19,8 @@ type FormValues = InferType; */ const SelectWrapper = (props: Omit, 'control'>) => { const form = useForm({ - defaultValues: { color: '' }, - resolver: yupResolver(formSchema), + defaultValues: {}, + resolver: zodResolver(formSchema), }); const onSubmit = () => {}; diff --git a/src/common/components/Form/__tests__/Textarea.test.tsx b/src/common/components/Form/__tests__/Textarea.test.tsx index df5c220..06e1d32 100644 --- a/src/common/components/Form/__tests__/Textarea.test.tsx +++ b/src/common/components/Form/__tests__/Textarea.test.tsx @@ -1,18 +1,17 @@ import { describe, expect, it } from 'vitest'; import userEvent from '@testing-library/user-event'; -import { InferType, object, string } from 'yup'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { render, screen } from 'test/test-utils'; import Textarea, { TextareaProps } from '../Textarea'; -const formSchema = object({ - myField: string().required('Required'), +const formSchema = z.object({ + myField: z.string().min(1, { message: 'Required' }), }); - -type FormValues = InferType; +type FormValues = z.infer; /** * A wrapper for testing the `Textarea` component which requires some @@ -21,7 +20,7 @@ type FormValues = InferType; const TextareaWrapper = (props: Omit, 'control'>) => { const form = useForm({ defaultValues: { myField: '' }, - resolver: yupResolver(formSchema), + resolver: zodResolver(formSchema), }); const onSubmit = () => {}; diff --git a/src/common/components/Form/__tests__/Toggle.test.tsx b/src/common/components/Form/__tests__/Toggle.test.tsx index ad72000..9909f1f 100644 --- a/src/common/components/Form/__tests__/Toggle.test.tsx +++ b/src/common/components/Form/__tests__/Toggle.test.tsx @@ -1,18 +1,19 @@ import userEvent from '@testing-library/user-event'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { boolean, InferType, object } from 'yup'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { describe, expect, it } from 'vitest'; import { render, screen } from 'test/test-utils'; import Toggle, { ToggleProps } from '../Toggle'; -const formSchema = object({ - myField: boolean().oneOf([false]), +const formSchema = z.object({ + myField: z.boolean().refine((val) => val === false, { + message: 'Must be false.', + }), }); - -type FormValues = InferType; +type FormValues = z.infer; /** * A wrapper for testing the `Toggle` component which requires some @@ -20,8 +21,8 @@ type FormValues = InferType; */ const ToggleWrapper = (props: Omit, 'control'>) => { const form = useForm({ - defaultValues: { myField: false }, - resolver: yupResolver(formSchema), + defaultValues: { myField: undefined }, + resolver: zodResolver(formSchema), }); const onSubmit = () => {}; @@ -78,6 +79,6 @@ describe('Toggle', () => { await screen.findByTestId('toggle-error'); // ASSERT - expect(screen.getByTestId('toggle-error')).toHaveTextContent(/must be one of the following/i); + expect(screen.getByTestId('toggle-error')).toHaveTextContent(/must be false/i); }); }); diff --git a/src/common/providers/ConfigProvider.tsx b/src/common/providers/ConfigProvider.tsx index 68dcd99..f9c5e19 100644 --- a/src/common/providers/ConfigProvider.tsx +++ b/src/common/providers/ConfigProvider.tsx @@ -1,23 +1,22 @@ import { PropsWithChildren, useEffect, useState } from 'react'; -import { number, object, ObjectSchema, string, ValidationError } from 'yup'; +import { z, ZodError } from 'zod'; import { Config, ConfigContext } from './ConfigContext'; /** * The configuration validation schema. - * @see {@link https://github.com/jquense/yup | Yup} */ -const configSchema: ObjectSchema = object({ - VITE_BASE_URL_API: string().url().required(), - VITE_BUILD_DATE: string().default('1970-01-01'), - VITE_BUILD_TIME: string().default('00:00:00'), - VITE_BUILD_TS: string().default('1970-01-01T00:00:00+0000'), - VITE_BUILD_COMMIT_SHA: string().default('local'), - VITE_BUILD_ENV_CODE: string().default('local'), - VITE_BUILD_WORKFLOW_NAME: string().default('local'), - VITE_BUILD_WORKFLOW_RUN_NUMBER: number().default(1), - VITE_BUILD_WORKFLOW_RUN_ATTEMPT: number().default(1), - VITE_TOAST_AUTO_DISMISS_MILLIS: number().default(5000), +const configSchema = z.object({ + VITE_BASE_URL_API: z.string().url(), + VITE_BUILD_DATE: z.string().default('1970-01-01'), + VITE_BUILD_TIME: z.string().default('00:00:00'), + VITE_BUILD_TS: z.string().default('1970-01-01T00:00:00+0000'), + VITE_BUILD_COMMIT_SHA: z.string().default('local'), + VITE_BUILD_ENV_CODE: z.string().default('local'), + VITE_BUILD_WORKFLOW_NAME: z.string().default('local'), + VITE_BUILD_WORKFLOW_RUN_NUMBER: z.coerce.number().default(1), + VITE_BUILD_WORKFLOW_RUN_ATTEMPT: z.coerce.number().default(1), + VITE_TOAST_AUTO_DISMISS_MILLIS: z.coerce.number().default(5000), }); /** @@ -35,14 +34,14 @@ const ConfigContextProvider = ({ children }: PropsWithChildren): JSX.Element => useEffect(() => { try { - const validatedConfig = configSchema.validateSync(import.meta.env, { - abortEarly: false, - stripUnknown: true, - }); + const validatedConfig = configSchema.parse(import.meta.env); setConfig(validatedConfig); setIsReady(true); } catch (err) { - if (err instanceof ValidationError) throw new Error(`${err}::${err.errors}`); + if (err instanceof ZodError) { + const errors = err.errors.map((e) => `${e.path.join('.')}::${e.message}`); + throw new Error(`Configuration error: ${errors.join(', ')}`); + } if (err instanceof Error) throw new Error(`Configuration error: ${err.message}`); throw err; } diff --git a/src/pages/Auth/Signin/components/SigninForm.tsx b/src/pages/Auth/Signin/components/SigninForm.tsx index 27e6679..23e78bf 100644 --- a/src/pages/Auth/Signin/components/SigninForm.tsx +++ b/src/pages/Auth/Signin/components/SigninForm.tsx @@ -1,9 +1,9 @@ import { useState } from 'react'; -import { object, string } from 'yup'; import { useNavigate } from 'react-router-dom'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; import { useTranslation } from 'react-i18next'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { cn } from 'common/utils/css'; import { BaseComponentProps } from 'common/utils/types'; @@ -41,11 +41,12 @@ const SigninForm = ({ className, testId = 'form-signin' }: BaseComponentProps): /** * Signin form validation schema. */ - const validationSchema = object({ - password: string().required(t('validation.required')), - username: string() - .required(t('validation.required')) - .max(30, t('validation.max', { count: 30 })), + const schema = z.object({ + password: z.string().min(1, { message: t('validation.required') }), + username: z + .string() + .min(1, { message: t('validation.required') }) + .max(30, { message: t('validation.max', { count: 30 }) }), }); /** @@ -54,7 +55,7 @@ const SigninForm = ({ className, testId = 'form-signin' }: BaseComponentProps): const { control, formState, handleSubmit } = useForm({ defaultValues: { username: '', password: '' }, mode: 'all', - resolver: yupResolver(validationSchema), + resolver: zodResolver(schema), }); /** diff --git a/src/pages/Components/components/InputComponents.tsx b/src/pages/Components/components/InputComponents.tsx index d09b15f..8cef9fa 100644 --- a/src/pages/Components/components/InputComponents.tsx +++ b/src/pages/Components/components/InputComponents.tsx @@ -1,8 +1,8 @@ import { ColumnDef, createColumnHelper } from '@tanstack/react-table'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { object, string } from 'yup'; import noop from 'lodash/noop'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { BaseComponentProps } from 'common/utils/types'; import { ComponentProperty } from '../model/components'; @@ -60,6 +60,12 @@ const InputComponents = ({ }), ] as ColumnDef[]; + /* example setup */ + const formSchema = z.object({ + firstName: z.string(), + middleInitial: z.string(), + lastName: z.string().min(1, { message: 'Last name is required.' }), + }); const { control, handleSubmit, reset } = useForm({ defaultValues: { firstName: '', @@ -67,13 +73,7 @@ const InputComponents = ({ lastName: '', }, mode: 'all', - resolver: yupResolver( - object({ - firstName: string(), - middleInitial: string(), - lastName: string().required('Last name is required.'), - }), - ), + resolver: zodResolver(formSchema), }); const onSubmit = noop; diff --git a/src/pages/Components/components/SelectComponents.tsx b/src/pages/Components/components/SelectComponents.tsx index 552cc40..9ce5cac 100644 --- a/src/pages/Components/components/SelectComponents.tsx +++ b/src/pages/Components/components/SelectComponents.tsx @@ -1,8 +1,8 @@ import { ColumnDef, createColumnHelper } from '@tanstack/react-table'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { object, string } from 'yup'; import noop from 'lodash/noop'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { BaseComponentProps } from 'common/utils/types'; import { ComponentProperty } from '../model/components'; @@ -60,20 +60,24 @@ const SelectComponents = ({ }), ] as ColumnDef[]; + /* example setup */ + const formSchema = z.object({ + color: z + .string() + .min(1, { message: 'Required' }) + .refine((val) => ['blue', 'red', 'yellow'].includes(val), { + message: 'You must select a primary color.', + }), + food: z.string().min(1, { message: 'Required' }), + }); + const { control, handleSubmit, reset } = useForm({ defaultValues: { color: '', food: '', }, mode: 'all', - resolver: yupResolver( - object({ - color: string() - .required('Color is required.') - .oneOf(['blue', 'red', 'yellow'], 'You must select a primary color.'), - food: string().required('Food is required.'), - }), - ), + resolver: zodResolver(formSchema), }); const onSubmit = noop; diff --git a/src/pages/Components/components/TextareaComponents.tsx b/src/pages/Components/components/TextareaComponents.tsx index d6914d5..f2487f8 100644 --- a/src/pages/Components/components/TextareaComponents.tsx +++ b/src/pages/Components/components/TextareaComponents.tsx @@ -1,8 +1,8 @@ import { ColumnDef, createColumnHelper } from '@tanstack/react-table'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { object, string } from 'yup'; import noop from 'lodash/noop'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { BaseComponentProps } from 'common/utils/types'; import { ComponentProperty } from '../model/components'; @@ -60,18 +60,20 @@ const TextareaComponents = ({ }), ] as ColumnDef[]; + /* example setup */ + const formSchema = z.object({ + bio: z + .string() + .min(1, { message: 'Your bio is required.' }) + .max(20, { message: 'Your bio may not be longer than 20 characters.' }), + }); + const { control, handleSubmit, reset } = useForm({ defaultValues: { bio: '', }, mode: 'all', - resolver: yupResolver( - object({ - bio: string() - .required('Your bio is required.') - .max(20, 'Your bio may not be longer than 20 characters.'), - }), - ), + resolver: zodResolver(formSchema), }); const onSubmit = noop; diff --git a/src/pages/Components/components/ToggleComponents.tsx b/src/pages/Components/components/ToggleComponents.tsx index 9919d3d..586a755 100644 --- a/src/pages/Components/components/ToggleComponents.tsx +++ b/src/pages/Components/components/ToggleComponents.tsx @@ -1,8 +1,8 @@ import { ColumnDef, createColumnHelper } from '@tanstack/react-table'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { boolean, object } from 'yup'; import noop from 'lodash/noop'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { BaseComponentProps } from 'common/utils/types'; import { ComponentProperty } from '../model/components'; @@ -68,16 +68,16 @@ const ToggleComponents = ({ }), ] as ColumnDef[]; + /* example setup */ + const formSchema = z.object({ + isNotificationsEnabled: z.boolean(), + }); const { control, handleSubmit, reset } = useForm({ defaultValues: { isNotificationsEnabled: true, }, mode: 'all', - resolver: yupResolver( - object({ - isNotificationsEnabled: boolean(), - }), - ), + resolver: zodResolver(formSchema), }); const onSubmit = noop; diff --git a/src/pages/Tasks/components/Form/TaskForm.tsx b/src/pages/Tasks/components/Form/TaskForm.tsx index 5999afd..113d57e 100644 --- a/src/pages/Tasks/components/Form/TaskForm.tsx +++ b/src/pages/Tasks/components/Form/TaskForm.tsx @@ -1,7 +1,7 @@ -import { boolean, number, object, string } from 'yup'; import { useForm } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; import { useTranslation } from 'react-i18next'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; import { cn } from 'common/utils/css'; import { BaseComponentProps } from 'common/utils/types'; @@ -49,12 +49,13 @@ const TaskForm = ({ /** * Task form validation schema. */ - const validationSchema = object({ - userId: number().required(t('validation.required')), - title: string() - .required(t('validation.required')) - .max(100, t('validation.max', { count: 100 })), - completed: boolean().required(t('validation.required')).default(false), + const schema = z.object({ + userId: z.number().min(1, { message: t('validation.required') }), + title: z + .string() + .min(1, { message: t('validation.required') }) + .max(100, { message: t('validation.max', { count: 100 }) }), + completed: z.boolean().default(false), }); /** @@ -67,7 +68,7 @@ const TaskForm = ({ completed: task?.completed || false, }, mode: 'all', - resolver: yupResolver(validationSchema), + resolver: zodResolver(schema), }); return ( diff --git a/src/pages/Tasks/components/Form/__tests__/TaskForm.test.tsx b/src/pages/Tasks/components/Form/__tests__/TaskForm.test.tsx index f24dae9..13ff988 100644 --- a/src/pages/Tasks/components/Form/__tests__/TaskForm.test.tsx +++ b/src/pages/Tasks/components/Form/__tests__/TaskForm.test.tsx @@ -47,12 +47,18 @@ describe('TaskForm', () => { expect(onCancelSpy).toHaveBeenCalled(); }); - it('should call onSubmit when cancelled', async () => { + it('should call onSubmit when submitted', async () => { // ARRANGE const onCancelSpy = vi.fn(); const onSubmitSpy = vi.fn(); const user = userEvent.setup(); - render(); + render( + , + ); await screen.findByTestId('task-form-button-submit'); // ACT From ff1d8c6630dc5bf381f275c57fef59dc85e004b4 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Thu, 3 Apr 2025 15:16:32 -0400 Subject: [PATCH 3/7] #106 remove yup --- package-lock.json | 32 +------------------------------- package.json | 1 - 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 666be6e..84d74d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,6 @@ "tailwind-merge": "3.1.0", "tailwindcss": "4.1.1", "uuid": "11.1.0", - "yup": "1.6.1", "zod": "3.24.2" }, "devDependencies": { @@ -7733,12 +7732,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/property-expr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", - "license": "MIT" - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -8882,12 +8875,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/tiny-case": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", - "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", - "license": "MIT" - }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -8971,12 +8958,6 @@ "node": ">=8.0" } }, - "node_modules/toposort": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", - "license": "MIT" - }, "node_modules/tough-cookie": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", @@ -9084,6 +9065,7 @@ "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=12.20" @@ -9853,18 +9835,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yup": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz", - "integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==", - "license": "MIT", - "dependencies": { - "property-expr": "^2.0.5", - "tiny-case": "^1.0.3", - "toposort": "^2.0.2", - "type-fest": "^2.19.0" - } - }, "node_modules/zod": { "version": "3.24.2", "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", diff --git a/package.json b/package.json index 844366d..aee8dda 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "tailwind-merge": "3.1.0", "tailwindcss": "4.1.1", "uuid": "11.1.0", - "yup": "1.6.1", "zod": "3.24.2" }, "devDependencies": { From eeb0faf0b7d89b6636d9aa12a77891971676cb5d Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Thu, 3 Apr 2025 15:19:47 -0400 Subject: [PATCH 4/7] #106 docs --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2656db3..8c6d6fa 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ The production technology stack includes: - Font Awesome - iconography - Google Fonts - typography - React i18next - internationalization -- Yup - schema based validation +- Zod - schema based validation - Lodash - utility functions - DayJS - date and time utility functions - TanStack Table - advanced tables and datagrids @@ -268,7 +268,7 @@ This project uses GitHub Actions to perform DevOps automation activities such as - [TanStack][tanstack] - [Axios][axios] - [React Hook Form][reacthookform] -- [Yup][yup] +- [Zod][zod] - [Tailwind CSS][tailwind] - [Class Variance Authority][cva] - [Font Awesome][fontawesome] @@ -287,7 +287,6 @@ This project uses GitHub Actions to perform DevOps automation activities such as [vite]: https://vitejs.dev/ 'Vite' [axios]: https://axios-http.com/ 'Axios' [reacthookform]: https://www.react-hook-form.com/ 'React Hook Form' -[yup]: https://github.com/jquense/yup 'Yup' [tailwind]: https://tailwindcss.com/ 'Tailwind CSS' [cva]: https://cva.style/ 'Class Variance Authority' [fontawesome]: https://fontawesome.com/ 'Font Awesome' @@ -298,3 +297,4 @@ This project uses GitHub Actions to perform DevOps automation activities such as [reactspring]: https://www.react-spring.dev/ 'React Spring' [storybook]: https://storybook.js.org/ 'Storybook' [recharts]: https://recharts.org/ 'Recharts' +[zod]: https://zod.dev/ 'Zod' From dbfcb9c6aed4d7b5a4a77d3c80ad8ff011fe265b Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Fri, 4 Apr 2025 06:34:57 -0400 Subject: [PATCH 5/7] #106 tests --- src/common/components/Form/__tests__/Select.test.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/common/components/Form/__tests__/Select.test.tsx b/src/common/components/Form/__tests__/Select.test.tsx index 3c8ac90..78f4699 100644 --- a/src/common/components/Form/__tests__/Select.test.tsx +++ b/src/common/components/Form/__tests__/Select.test.tsx @@ -9,7 +9,7 @@ import { render, screen, waitFor } from 'test/test-utils'; import Select, { SelectProps } from '../Select'; const formSchema = z.object({ - color: z.enum(['blue'], { message: 'Must select a value in the list.' }), + color: z.string().refine((val) => ['blue'].includes(val), { message: 'Must select blue.' }), }); type FormValues = z.infer; @@ -256,8 +256,6 @@ describe('Select', () => { await screen.findByTestId('select-error'); // ASSERT - expect(screen.getByTestId('select-error')).toHaveTextContent( - /must select a value in the list/i, - ); + expect(screen.getByTestId('select-error')).toHaveTextContent(/must select blue/i); }); }); From 22dc7265ea399c785e9aa0919ceeb9a78193c334 Mon Sep 17 00:00:00 2001 From: Matthew Warman Date: Fri, 4 Apr 2025 06:40:21 -0400 Subject: [PATCH 6/7] #106 tests --- .../Components/components/SelectComponents.tsx | 6 ++++-- .../components/__tests__/SelectComponents.test.tsx | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/pages/Components/components/SelectComponents.tsx b/src/pages/Components/components/SelectComponents.tsx index 9ce5cac..8613478 100644 --- a/src/pages/Components/components/SelectComponents.tsx +++ b/src/pages/Components/components/SelectComponents.tsx @@ -118,13 +118,15 @@ const SelectComponents = ({ {/* Example */}