diff --git a/package-lock.json b/package-lock.json index bfe9014c..de8c08c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3468,6 +3468,16 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hookform/error-message": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@hookform/error-message/-/error-message-2.0.1.tgz", + "integrity": "sha512-U410sAr92xgxT1idlu9WWOVjndxLdgPUHEB8Schr27C9eh7/xUnITWpCMF93s+lGiG++D4JnbSnrb5A21AdSNg==", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "react-hook-form": "^7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -7760,10 +7770,6 @@ "resolved": "packages/haring-react-dropzone", "link": true }, - "node_modules/@smile/haring-react-hook-form": { - "resolved": "packages/haring-react-hook-form", - "link": true - }, "node_modules/@smile/haring-react-shared": { "resolved": "packages/haring-react-shared", "link": true @@ -34485,6 +34491,7 @@ "packages/haring-react-hook-form": { "name": "@smile/haring-react-hook-form", "version": "0.15.0", + "extraneous": true, "license": "LGPL-3.0", "dependencies": { "@smile/haring-react": "0.15.0", @@ -34523,496 +34530,6 @@ "react-hook-form": "^7.52.2" } }, - "packages/haring-react-hook-form/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "packages/haring-react-hook-form/node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "packages/haring-react-hook-form/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "packages/haring-react-hook-form/node_modules/rollup": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz", - "integrity": "sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.0", - "@rollup/rollup-android-arm64": "4.21.0", - "@rollup/rollup-darwin-arm64": "4.21.0", - "@rollup/rollup-darwin-x64": "4.21.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.0", - "@rollup/rollup-linux-arm-musleabihf": "4.21.0", - "@rollup/rollup-linux-arm64-gnu": "4.21.0", - "@rollup/rollup-linux-arm64-musl": "4.21.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.0", - "@rollup/rollup-linux-riscv64-gnu": "4.21.0", - "@rollup/rollup-linux-s390x-gnu": "4.21.0", - "@rollup/rollup-linux-x64-gnu": "4.21.0", - "@rollup/rollup-linux-x64-musl": "4.21.0", - "@rollup/rollup-win32-arm64-msvc": "4.21.0", - "@rollup/rollup-win32-ia32-msvc": "4.21.0", - "@rollup/rollup-win32-x64-msvc": "4.21.0", - "fsevents": "~2.3.2" - } - }, - "packages/haring-react-hook-form/node_modules/vite": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.1.tgz", - "integrity": "sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==", - "dev": true, - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.41", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, "packages/haring-react-shared": { "name": "@smile/haring-react-shared", "version": "0.15.0", @@ -36567,6 +36084,7 @@ "version": "0.15.0", "license": "LGPL-3.0", "dependencies": { + "@hookform/error-message": "^2.0.1", "@mantine/carousel": "^7.11.0", "@mantine/charts": "^7.11.0", "@mantine/form": "^7.11.0", @@ -36585,12 +36103,14 @@ "vite-plugin-dts": "^3.7.2" }, "peerDependencies": { + "@hookform/error-message": "^2.0.1", "@mantine/core": ">=7.11.0", "@mantine/dates": ">=7.11.0", "@mantine/hooks": ">=7.11.0", "@phosphor-icons/react": ">=2", "react": ">=18.0", - "react-dom": ">=18.0" + "react-dom": ">=18.0", + "react-hook-form": "^7.52.2" } }, "packages/storybook-pages/node_modules/@esbuild/android-arm": { diff --git a/packages/haring-react-hook-form/CHANGELOG.md b/packages/haring-react-hook-form/CHANGELOG.md deleted file mode 100644 index e21ea6e9..00000000 --- a/packages/haring-react-hook-form/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -# @smile/haring-react-hook-form diff --git a/packages/haring-react-hook-form/README.md b/packages/haring-react-hook-form/README.md deleted file mode 100644 index fb773475..00000000 --- a/packages/haring-react-hook-form/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# @smile/haring-react-hook-form - -React Hook Form related components. - -## Documentation - -You can access the documentation here: https://smile-sa.github.io/haring-doc - -## Prerequisite - -You must have React 18 or later installed on your project. - -## Installation - -You must install `@smile/haring-react` first and then install -`react-hook-form` peer dependencies with: - -```bash -npm i @smile/haring-react react-hook-form -``` - -## Styles - -Import the styles in your app with: - -```js -import '@smile/haring-react-hook-form/style.css'; -``` - -## License - -LGPL-3.0 diff --git a/packages/haring-react-hook-form/babel.config.cjs b/packages/haring-react-hook-form/babel.config.cjs deleted file mode 100644 index 52da6820..00000000 --- a/packages/haring-react-hook-form/babel.config.cjs +++ /dev/null @@ -1,3 +0,0 @@ -const { babelConfig } = require('test'); - -module.exports = babelConfig; diff --git a/packages/haring-react-hook-form/jest.config.ts b/packages/haring-react-hook-form/jest.config.ts deleted file mode 100644 index 84c5d09e..00000000 --- a/packages/haring-react-hook-form/jest.config.ts +++ /dev/null @@ -1 +0,0 @@ -export { jestConfig as default } from 'test'; diff --git a/packages/haring-react-hook-form/package.json b/packages/haring-react-hook-form/package.json deleted file mode 100644 index e0460bb0..00000000 --- a/packages/haring-react-hook-form/package.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "name": "@smile/haring-react-hook-form", - "version": "0.15.0", - "description": "React Hook Form component library based on mantine", - "license": "LGPL-3.0", - "homepage": "https://github.com/Smile-SA/haring", - "repository": { - "type": "git", - "url": "git@github.com:Smile-SA/haring.git" - }, - "bugs": { - "url": "https://github.com/Smile-SA/haring/issues" - }, - "keywords": [ - "react", - "react-component", - "next", - "nextjs", - "ui", - "components", - "ui-kit", - "library", - "frontend", - "design", - "form", - "react-hook-form" - ], - "author": { - "name": "Tony Cabaye", - "email": "tonai59+github@gmail.com", - "url": "https://github.com/tonai" - }, - "type": "module", - "exports": { - ".": { - "import": "./dist/index.js", - "require": "./dist/index.cjs", - "types": "./dist/index.d.ts" - }, - "./server": { - "import": "./dist/server.js", - "require": "./dist/server.cjs", - "types": "./dist/server.d.ts" - }, - "./style.css": "./dist/style.css" - }, - "types": "./dist/index.d.ts", - "typesVersions": { - "*": { - "server": [ - "./dist/server.d.ts" - ], - "mock": [ - "./dist/mock.d.ts" - ] - } - }, - "files": [ - "CHANGELOG.md", - "LICENSE", - "package.json", - "README.md", - "dist", - "src" - ], - "scripts": { - "build": "vite build", - "test": "jest", - "prepublishOnly": "npm run build && node ../../scripts/prepublish.mjs" - }, - "dependencies": { - "@smile/haring-react": "0.15.0", - "@smile/haring-react-shared": "0.15.0" - }, - "devDependencies": { - "@babel/preset-env": "^7.22.20", - "@babel/preset-react": "^7.22.15", - "@babel/preset-typescript": "^7.23.0", - "@storybook/addon-actions": "^7.4.1", - "@storybook/jest": "^0.2.2", - "@storybook/preview-api": "^7.4.1", - "@storybook/testing-library": "^0.2.0", - "@testing-library/jest-dom": "^6.1.3", - "@testing-library/react": "^14.0.0", - "@types/react": "^18.2.21", - "@types/react-dom": "^18.2.7", - "@vitejs/plugin-react-swc": "^3.5.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "test": "*", - "tsconfig": "*", - "typescript": "~5.2.0", - "vite": "^5.0.12", - "vite-plugin-dts": "^3.7.2" - }, - "peerDependencies": { - "@mantine/core": ">=7.11.0", - "@mantine/hooks": ">=7.11.0", - "react-hook-form": "^7.52.2", - "@phosphor-icons/react": ">=2", - "react": ">=18.0", - "react-dom": ">=18.0" - }, - "engines": { - "node": ">=16" - } -} diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.stories.tsx b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.stories.tsx deleted file mode 100644 index 0a6cb153..00000000 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.stories.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import type { IFormDynamicZoneProps } from './FormDynamicZone'; -import type { Meta, StoryObj } from '@storybook/react'; -import type { ReactElement } from 'react'; - -import { action } from '@storybook/addon-actions'; -import { FormProvider, useForm } from 'react-hook-form'; - -import { FormDynamicZone as Cmp } from './FormDynamicZone'; -import { dynamicBlocksMock } from './FormDynamicZone.mock'; - -const meta = { - component: Cmp, - tags: ['autodocs'], - title: '3-custom/Form/FormDynamicZone', -} satisfies Meta; - -export default meta; -type IStory = StoryObj; - -function render() { - return function Render(props: IFormDynamicZoneProps): ReactElement { - const methods = useForm(); - return ( - -
- -
-
- ); - }; -} - -export const FormDynamicZone: IStory = { - args: { - dynamicBlocks: dynamicBlocksMock, - dynamicZoneName: 'dynTest', - onFormSubmit: action('results'), - }, - render: render(), -}; diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.test.tsx b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.test.tsx deleted file mode 100644 index f5f2f9d5..00000000 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { ReactElement } from 'react'; - -import { renderWithProviders } from '@smile/haring-react-shared/test-utils'; -import { action } from '@storybook/addon-actions'; -import { FormProvider, useForm } from 'react-hook-form'; - -import { FormDynamicZone } from './FormDynamicZone'; -import { dynamicBlocksMock } from './FormDynamicZone.mock'; - -describe('FormDynamicZone', () => { - it('matches snapshot', () => { - function TestWithProvider(): ReactElement { - const methods = useForm(); - return ( - - - - ); - } - - const { container } = renderWithProviders(); - expect(container).toMatchSnapshot(); - }); -}); diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx b/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx deleted file mode 100644 index 0b88028f..00000000 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import type { - IFormDynBlock, - IFormDynSubmit, - IFormDynSubmitResults, - IFormField, - IFormFieldWithoutId, -} from '../../types'; -import type { IBaseBlockButton, IBaseBlockType } from '@smile/haring-react'; -import type { IDynamicZoneBlockReference } from '@smile/haring-react/src/Form/DynamicZone/DynamicZoneBlock/DynamicZoneBlock'; -import type { IAction } from '@smile/haring-react-shared'; -import type { ReactElement } from 'react'; - -import { Stack } from '@mantine/core'; -import { ArrowDown, ArrowUp, Trash } from '@phosphor-icons/react'; -import { DynamicZone } from '@smile/haring-react'; -import { useFieldArray, useFormContext } from 'react-hook-form'; - -interface IFormDynamicZoneActionLabels { - deleteLabel: string; - moveDownLabel: string; - moveUpLabel: string; -} - -const defaultActionLabels: IFormDynamicZoneActionLabels = { - deleteLabel: 'Delete', - moveDownLabel: 'Move Down', - moveUpLabel: 'Move Up', -}; - -export interface IFormDynamicZoneProps { - actionLabels?: IFormDynamicZoneActionLabels; - dynamicBlocks: IFormDynBlock[]; - dynamicZoneName: string; - onFormSubmit: (data: IFormDynSubmitResults) => void; -} - -export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement { - const { - dynamicBlocks, - dynamicZoneName, - actionLabels = defaultActionLabels, - onFormSubmit, - } = props; - - const { control, register, handleSubmit, getValues } = - useFormContext>(); - const { fields, append, remove, swap, update } = useFieldArray({ - control, - name: dynamicZoneName, - }); - const blockOptions: IBaseBlockButton[] = dynamicBlocks.map((b) => b.button); - - function renderBlock(block: IFormField, index: number): ReactElement { - const correspondingType = dynamicBlocks.find( - (b) => b.block.blockType === block.blockType, - ); - if (correspondingType === undefined) { - throw Error( - `Could not find an IFormDynBlock of blocktype '${block.blockType} in given dynamicBlocks'`, - ); - } - return correspondingType.renderFunc( - block, - index, - register, - `${dynamicZoneName}.${index}.value` as const, - ); - } - - function onRemove(ref: IDynamicZoneBlockReference): void { - remove(ref.index); - } - - function onSwap( - ref: IDynamicZoneBlockReference, - direction: 'down' | 'up', - ): void { - const secondIndex = ref.index + (direction === 'up' ? -1 : 1); - if (secondIndex >= 0 && secondIndex < ref.arrayLength) { - swap(ref.index, ref.index + (direction === 'up' ? -1 : 1)); - } - } - - function onToggle(_block: IFormField, index: number, opened: boolean): void { - const updatedBlock = getValues(dynamicZoneName)[index]; - update(index, { ...updatedBlock, opened }); - } - - function isMoveDisabled( - ref: IDynamicZoneBlockReference, - direction: 'down' | 'up', - ): boolean { - return direction === 'up' - ? ref.index === 0 - : ref.index === ref.arrayLength - 1; - } - - const formDynamicZoneDefaultActions: IAction[] = [ - { - componentProps: (ref) => ({ disabled: isMoveDisabled(ref, 'up') }), - icon: , - id: 'move-up', - label: actionLabels.moveUpLabel, - onAction: (ref) => onSwap(ref, 'up'), - }, - { - componentProps: (ref) => ({ disabled: isMoveDisabled(ref, 'down') }), - icon: , - id: 'move-down', - label: actionLabels.moveDownLabel, - onAction: (ref) => onSwap(ref, 'down'), - }, - { - icon: , - id: 'delete', - label: actionLabels.deleteLabel, - onAction: onRemove, - }, - ]; - - function onAppend(type: IBaseBlockType): void { - const correspondingType = dynamicBlocks.find( - (b) => b.block.blockType === type, - ); - if (correspondingType === undefined) { - throw Error( - `Could not find an IFormDynBlock of blocktype '${type} in given dynamicBlocks'`, - ); - } - append({ - ...correspondingType.block, - blockActions: formDynamicZoneDefaultActions, - }); - } - - function onSubmit(data: IFormDynSubmit): void { - onFormSubmit( - data[dynamicZoneName].map( - ({ blockActions, blockHeader, blockFooter, ...block }) => block, - ), - ); - } - - return ( - // eslint-disable-next-line @typescript-eslint/no-misused-promises -
- - - blockOptions={blockOptions} - blocks={fields} - fluid - m={0} - onAppendBlock={onAppend} - onRenderBlockContent={renderBlock} - onToggleBlock={onToggle} - /> - {/* TODO: Move this out, should be in the story/text not part of this component since it's just a field */} - {/* TODO: then decide how to send errors/messages upwards, where they can go (everything should be doable with props) */} - {/* TODO: build mock example of error messages and where they can go (at the form level, somewhere inside this component, in blocks... */} - {/* TODO: then focus and nested focus, multiple errors, auto-opening a block if it wants to focus inside, auto-scroll the page */} - {/* TODO: then animations */} - - -
- ); -} diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap b/packages/haring-react-hook-form/src/Components/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap deleted file mode 100644 index 9a52dfb1..00000000 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap +++ /dev/null @@ -1,121 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FormDynamicZone matches snapshot 1`] = ` -
- - -
-
-
-
-
-

-

- - -
-
-
- -
- -
-`; diff --git a/packages/haring-react-hook-form/src/index.tsx b/packages/haring-react-hook-form/src/index.tsx deleted file mode 100644 index f967c8a5..00000000 --- a/packages/haring-react-hook-form/src/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint-disable react-refresh/only-export-components */ -'use client'; - -// component exports -export { FormDynamicZone } from './Components/FormDynamicZone/FormDynamicZone'; -export type { IFormDynamicZoneProps } from './Components/FormDynamicZone/FormDynamicZone'; diff --git a/packages/haring-react-hook-form/src/types/form-dynamic-zone.ts b/packages/haring-react-hook-form/src/types/form-dynamic-zone.ts deleted file mode 100644 index 5a0a69f7..00000000 --- a/packages/haring-react-hook-form/src/types/form-dynamic-zone.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { IBaseBlock, IBaseBlockButton } from '@smile/haring-react'; -import type { IOmitRespectIndexSignature } from '@smile/haring-react-shared'; -import type { ReactElement } from 'react'; -import type { UseFormRegister } from 'react-hook-form/dist/types/form'; - -export interface IFormField extends IBaseBlock { - // fieldId: string; - value?: string; -} - -export interface IFormFieldWithoutId - extends IOmitRespectIndexSignature { - id?: never; // forbid property "id" from being declared, to never override the internal IBaseBlock.id which is only used by useFieldArray() -} - -export type IFormRegisterFunc< - T extends IFormFieldWithoutId = IFormFieldWithoutId, -> = UseFormRegister>; - -export interface IFormDynBlock { - block: IFormFieldWithoutId; - button: IBaseBlockButton; - renderFunc: ( - block: IFormField, - index: number, - registerFunc: IFormRegisterFunc, - registerName: string, - ) => ReactElement; -} - -export type IFormDynSubmit = Record; -export type IFormDynSubmitResults = IOmitRespectIndexSignature< - IFormFieldWithoutId, - 'blockActions' | 'blockFooter' | 'blockHeader' ->[]; diff --git a/packages/haring-react-hook-form/src/types/index.ts b/packages/haring-react-hook-form/src/types/index.ts deleted file mode 100644 index 152dcd45..00000000 --- a/packages/haring-react-hook-form/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './form-dynamic-zone'; diff --git a/packages/haring-react-hook-form/tsconfig.build.json b/packages/haring-react-hook-form/tsconfig.build.json deleted file mode 100644 index 988effdd..00000000 --- a/packages/haring-react-hook-form/tsconfig.build.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "tsconfig/react-library.json", - "compilerOptions": { - "outDir": "dist" - }, - "exclude": [ - "__snapshots__", - "src/**/*.test.tsx", - "src/**/*.stories.tsx", - "src/**/*.mock.tsx" - ], - "include": ["src", "../../global.d.ts"] -} diff --git a/packages/haring-react-hook-form/tsconfig.json b/packages/haring-react-hook-form/tsconfig.json deleted file mode 100644 index 01b29193..00000000 --- a/packages/haring-react-hook-form/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "tsconfig/react-library.json", - "compilerOptions": { - "plugins": [{ "name": "typescript-plugin-css-modules" }] - }, - "include": [".", "../../global.d.ts"] -} diff --git a/packages/haring-react-hook-form/vite.config.js b/packages/haring-react-hook-form/vite.config.js deleted file mode 100644 index de26987a..00000000 --- a/packages/haring-react-hook-form/vite.config.js +++ /dev/null @@ -1,53 +0,0 @@ -import { resolve } from 'path'; - -import react from '@vitejs/plugin-react-swc'; -import { defineConfig } from 'vite'; -import dts from 'vite-plugin-dts'; - -export default defineConfig({ - build: { - lib: { - entry: resolve(__dirname, 'src/index.tsx'), - fileName: '[name]', - formats: ['cjs', 'es'], - }, - rollupOptions: { - external: [ - '@mantine/core', - '@mantine/hooks', - '@phosphor-icons/react', - '@smile/haring-react', - '@smile/haring-react-shared', - '@storybook/addon-actions', - '@storybook/preview-api', - '@tabler/icons-react', - '@testing-library/react', - 'react', - 'react/jsx-runtime', - ], - input: { - index: resolve(__dirname, 'src/index.tsx'), - }, - output: { - banner: (chunkInfo) => { - if ( - ['src/index.tsx'].find((modulePath) => - chunkInfo.facadeModuleId?.endsWith(modulePath), - ) - ) { - return `"use client"`; - } - return ''; - }, - preserveModules: false, - }, - }, - }, - plugins: [ - react(), - dts({ - insertTypesEntry: true, - tsconfigPath: './tsconfig.build.json', - }), - ], -}); diff --git a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.mock.tsx b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.mock.tsx similarity index 57% rename from packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.mock.tsx rename to packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.mock.tsx index e26621bb..61ee433b 100644 --- a/packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.mock.tsx +++ b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.mock.tsx @@ -1,10 +1,41 @@ -import type { IFormDynBlock, IFormField, IFormRegisterFunc } from '../../types'; +import type { IBaseBlock, IFormDynamicZoneBlock } from '../../types'; import type { ReactElement } from 'react'; import { Group } from '@mantine/core'; import { Cube, Leaf } from '@phosphor-icons/react'; -export const dynamicBlocksMock: IFormDynBlock[] = [ +export interface IExampleBlock extends IBaseBlock { + value?: string; +} + +export const blocksMock: IExampleBlock[] = [ + { + blockHeader: ( + <> + + Example A + + ), + blockType: 'exampleA', + id: '0', + opened: true, + value: 'existing value', + }, + { + blockHeader: ( + <> + + Example B + + ), + blockType: 'exampleB', + id: '1', + opened: true, + value: 'selectB', + }, +]; + +export const availableBlocksMock: IFormDynamicZoneBlock[] = [ { block: { blockHeader: ( @@ -22,28 +53,19 @@ export const dynamicBlocksMock: IFormDynBlock[] = [ label: 'Example A', leftSection: , }, - renderFunc: ( - b: IFormField, - _i: number, - register: IFormRegisterFunc, - registerName: string, - ): ReactElement => { + renderFunc: (b: IExampleBlock, i: number): ReactElement => { return ( @@ -68,18 +90,9 @@ export const dynamicBlocksMock: IFormDynBlock[] = [ label: 'Example B', leftSection: , }, - renderFunc: ( - b: IFormField, - _i: number, - register: IFormRegisterFunc, - registerName: string, - ): ReactElement => { + renderFunc: (b: IExampleBlock, i: number): ReactElement => { return ( - diff --git a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.stories.tsx b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.stories.tsx new file mode 100644 index 00000000..0f09364e --- /dev/null +++ b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.stories.tsx @@ -0,0 +1,24 @@ +import type { IExampleBlock } from './FormDynamicZone.mock'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { action } from '@storybook/addon-actions'; + +import { FormDynamicZone as Cmp } from './FormDynamicZone'; +import { availableBlocksMock, blocksMock } from './FormDynamicZone.mock'; + +const meta = { + component: Cmp, + tags: ['autodocs'], + title: '3-custom/Form/FormDynamicZone', +} satisfies Meta>; + +export default meta; +type IStory = StoryObj; + +export const FormDynamicZone: IStory = { + args: { + availableBlocks: availableBlocksMock, + blocksArray: blocksMock, + onUpdatedArray: action('results'), + }, +}; diff --git a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.test.tsx b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.test.tsx new file mode 100644 index 00000000..e52ecfdc --- /dev/null +++ b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.test.tsx @@ -0,0 +1,20 @@ +import type { IExampleBlock } from './FormDynamicZone.mock'; + +import { renderWithProviders } from '@smile/haring-react-shared/test-utils'; +import { action } from '@storybook/addon-actions'; + +import { FormDynamicZone } from './FormDynamicZone'; +import { availableBlocksMock, blocksMock } from './FormDynamicZone.mock'; + +describe('FormDynamicZone', () => { + it('matches snapshot', () => { + const { container } = renderWithProviders( + + availableBlocks={availableBlocksMock} + blocksArray={blocksMock} + onUpdatedArray={action('onUpdatedArray')} + />, + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.tsx b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.tsx new file mode 100644 index 00000000..83e3e974 --- /dev/null +++ b/packages/haring-react/src/Form/FormDynamicZone/FormDynamicZone.tsx @@ -0,0 +1,148 @@ +import type { IBaseBlock, IFormDynamicZoneBlock } from '../../types'; +import type { IBaseBlockButton, IBaseBlockType } from '@smile/haring-react'; +import type { IDynamicZoneBlockReference } from '@smile/haring-react/src/Form/DynamicZone/DynamicZoneBlock/DynamicZoneBlock'; +import type { IAction } from '@smile/haring-react-shared'; +import type { ReactElement } from 'react'; + +import { ArrowDown, ArrowUp, Trash } from '@phosphor-icons/react'; + +import { DynamicZone } from '../DynamicZone/DynamicZone'; + +interface IFormDynamicZoneActionLabels { + deleteLabel: string; + moveDownLabel: string; + moveUpLabel: string; +} + +const defaultActionLabels: IFormDynamicZoneActionLabels = { + deleteLabel: 'Delete', + moveDownLabel: 'Move Down', + moveUpLabel: 'Move Up', +}; + +export interface IFormDynamicZoneProps { + actionLabels?: IFormDynamicZoneActionLabels; + availableBlocks: IFormDynamicZoneBlock[]; + blocksArray: T[]; + onUpdatedArray: (newBlocksArray: T[]) => void; +} + +export function FormDynamicZone( + props: IFormDynamicZoneProps, +): ReactElement { + const { + actionLabels = defaultActionLabels, + availableBlocks, + blocksArray, + onUpdatedArray, + } = props; + + const blockOptions: IBaseBlockButton[] = availableBlocks.map((b) => b.button); + + function renderBlock(block: T, index: number): ReactElement { + const correspondingType = availableBlocks.find( + (b) => b.block.blockType === block.blockType, + ); + if (correspondingType === undefined) { + throw Error( + `Could not render a block of blockType '${block.blockType} in given IFormDynamicZoneBlock[]'`, + ); + } + return correspondingType.renderFunc(block, index); + } + + function onRemove(ref: IDynamicZoneBlockReference): void { + const newArray = [...blocksArray]; + delete newArray[ref.index]; + onUpdatedArray(newArray); + } + + function onSwap( + ref: IDynamicZoneBlockReference, + direction: 'down' | 'up', + ): void { + const secondIndex = ref.index + (direction === 'up' ? -1 : 1); + if (secondIndex >= 0 && secondIndex < ref.arrayLength) { + const newArray = [...blocksArray]; + // swap two elements in array + newArray[ref.index] = newArray.splice( + secondIndex, + 1, + newArray[ref.index], + )[0]; + onUpdatedArray(newArray); + } + } + + function onToggle(_block: T, index: number, opened: boolean): void { + const newArray = [...blocksArray]; + newArray[index] = { ...newArray[index], opened }; + onUpdatedArray(newArray); + } + + function isMoveDisabled( + ref: IDynamicZoneBlockReference, + direction: 'down' | 'up', + ): boolean { + return direction === 'up' + ? ref.index === 0 + : ref.index === ref.arrayLength - 1; + } + + const formDynamicZoneDefaultActions: IAction[] = [ + { + componentProps: (ref) => ({ disabled: isMoveDisabled(ref, 'up') }), + icon: , + id: 'move-up', + label: actionLabels.moveUpLabel, + onAction: (ref) => onSwap(ref, 'up'), + }, + { + componentProps: (ref) => ({ disabled: isMoveDisabled(ref, 'down') }), + icon: , + id: 'move-down', + label: actionLabels.moveDownLabel, + onAction: (ref) => onSwap(ref, 'down'), + }, + { + icon: , + id: 'delete', + label: actionLabels.deleteLabel, + onAction: onRemove, + }, + ]; + + function onAppend(type: IBaseBlockType): void { + const correspondingType = availableBlocks.find( + (b) => b.block.blockType === type, + ); + if (correspondingType === undefined) { + throw Error( + `Could not append a block of blockType '${type} in given IFormDynamicZoneBlock[]'`, + ); + } + const newArray = [...blocksArray]; + newArray.push({ + ...(correspondingType.block as T), + id: crypto.randomUUID(), + }); + onUpdatedArray(newArray); + } + + const blocksWithActions = blocksArray.map((b) => ({ + ...b, + blockActions: formDynamicZoneDefaultActions, + })); + + return ( + + blockOptions={blockOptions} + blocks={blocksWithActions} + fluid + m={0} + onAppendBlock={onAppend} + onRenderBlockContent={renderBlock} + onToggleBlock={onToggle} + /> + ); +} diff --git a/packages/haring-react/src/Form/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap b/packages/haring-react/src/Form/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap new file mode 100644 index 00000000..e24ff726 --- /dev/null +++ b/packages/haring-react/src/Form/FormDynamicZone/__snapshots__/FormDynamicZone.test.tsx.snap @@ -0,0 +1,457 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FormDynamicZone matches snapshot 1`] = ` +
+ + +
+
+
+
+
+
+ +
+ + + + + Example A + +
+
+ + + +
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+ +
+ + + + + Example B + +
+
+ + + +
+
+
+
+
+ +
+
+
+
+
+
+

+

+ + +
+
+
+
+`; diff --git a/packages/haring-react/src/index.tsx b/packages/haring-react/src/index.tsx index 89c27f84..7278b6f8 100644 --- a/packages/haring-react/src/index.tsx +++ b/packages/haring-react/src/index.tsx @@ -12,6 +12,8 @@ export type { IAddressAutocompleteFieldProps } from './Form/AddressGouvAutocompl export { AddressGouvAutocompleteField } from './Form/AddressGouvAutocompleteField/AddressGouvAutocompleteField'; export type { IDynamicZoneProps } from './Form/DynamicZone/DynamicZone'; export { DynamicZone } from './Form/DynamicZone/DynamicZone'; +export type { IFormDynamicZoneProps } from './Form/FormDynamicZone/FormDynamicZone'; +export { FormDynamicZone } from './Form/FormDynamicZone/FormDynamicZone'; export type { IAddressFieldsProps } from './Form/AddressFields/AddressFields'; export { AddressFields } from './Form/AddressFields/AddressFields'; export type { IIconCardProps } from './Components/IconCard/IconCard'; @@ -133,4 +135,5 @@ export type { IBaseBlock, IBaseBlockButton, IBaseBlockType, + IFormDynamicZoneBlock, } from './types'; diff --git a/packages/haring-react/src/types/dynamic-zone.ts b/packages/haring-react/src/types/dynamic-zone.ts index 479dcb43..60a1bb3d 100644 --- a/packages/haring-react/src/types/dynamic-zone.ts +++ b/packages/haring-react/src/types/dynamic-zone.ts @@ -1,7 +1,10 @@ import type { IDynamicZoneBlockReference } from '../Form/DynamicZone/DynamicZoneBlock/DynamicZoneBlock'; import type { ButtonProps } from '@mantine/core'; -import type { IAction } from '@smile/haring-react-shared'; -import type { ReactNode } from 'react'; +import type { + IAction, + IOmitRespectIndexSignature, +} from '@smile/haring-react-shared'; +import type { ReactElement, ReactNode } from 'react'; export type IBaseBlockType = string; @@ -14,7 +17,20 @@ export interface IBaseBlock extends Record { opened: boolean; } +// TODO: wip, try replacing the type of the blocks array with this rather than BaseBlock, will require a bunch of changes in FormDynamicZone and with +export interface IBlock extends Record { + blockType: IBaseBlockType; + readonly id: string; + opened: boolean; +} + export interface IBaseBlockButton extends ButtonProps { blockType: IBaseBlockType; label: string; } + +export interface IFormDynamicZoneBlock { + block: IOmitRespectIndexSignature; + button: IBaseBlockButton; + renderFunc: (block: T, index: number) => ReactElement; +} diff --git a/packages/storybook-pages/package.json b/packages/storybook-pages/package.json index f80feca5..f48614d5 100644 --- a/packages/storybook-pages/package.json +++ b/packages/storybook-pages/package.json @@ -29,6 +29,7 @@ "@smile/haring-react-table": "*", "embla-carousel-react": "^7.1.0", "react-hook-form": "^7.50.1", + "@hookform/error-message": "^2.0.1", "recharts": "^2.12.3" }, "devDependencies": { @@ -41,6 +42,8 @@ "@mantine/core": ">=7.11.0", "@mantine/dates": ">=7.11.0", "@mantine/hooks": ">=7.11.0", + "react-hook-form": "^7.52.2", + "@hookform/error-message": "^2.0.1", "@phosphor-icons/react": ">=2", "react": ">=18.0", "react-dom": ">=18.0" diff --git a/packages/storybook-pages/src/Form/ReactHookFormDynamicZone/ReactHookFormDynamicZone.stories.tsx b/packages/storybook-pages/src/Form/ReactHookFormDynamicZone/ReactHookFormDynamicZone.stories.tsx new file mode 100644 index 00000000..4362f07e --- /dev/null +++ b/packages/storybook-pages/src/Form/ReactHookFormDynamicZone/ReactHookFormDynamicZone.stories.tsx @@ -0,0 +1,20 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { action } from '@storybook/addon-actions'; + +import { ReactHookFormDynamicZone } from './ReactHookFormDynamicZone'; + +const meta = { + component: ReactHookFormDynamicZone, + title: '2-mantine/Form', +} satisfies Meta; + +export default meta; +type IStory = StoryObj; + +export const FormDynamicZoneExample: IStory = { + args: { + onFormErrors: action('Form Errors'), + onFormSubmit: action('Form Submit'), + }, +}; diff --git a/packages/storybook-pages/src/Form/ReactHookFormDynamicZone/ReactHookFormDynamicZone.tsx b/packages/storybook-pages/src/Form/ReactHookFormDynamicZone/ReactHookFormDynamicZone.tsx new file mode 100644 index 00000000..85fedf45 --- /dev/null +++ b/packages/storybook-pages/src/Form/ReactHookFormDynamicZone/ReactHookFormDynamicZone.tsx @@ -0,0 +1,180 @@ +import type { IExampleBlock } from '@smile/haring-react/src/Form/FormDynamicZone/FormDynamicZone.mock'; +import type { + IBaseBlock, + IFormDynamicZoneBlock, +} from '@smile/haring-react/src/types'; +import type { ReactElement } from 'react'; +import type { + FieldErrors, + SubmitErrorHandler, + SubmitHandler, +} from 'react-hook-form'; + +import { Box, Group, Stack } from '@mantine/core'; +import { Cube, Leaf } from '@phosphor-icons/react'; +import { FormDynamicZone } from '@smile/haring-react'; +import { useFieldArray, useForm } from 'react-hook-form'; + +import { withExceptionCapturing } from '../utilities/react-hook-form-utilities'; + +interface IContentA extends IBaseBlock { + value: string; +} + +interface IContentB extends IBaseBlock { + selected: string; +} + +type IDynamicContents = IContentA | IContentB; + +const initialBlocks: IDynamicContents[] = [ + { + blockType: 'exampleA', + id: '0', + opened: true, + }, + { + blockType: 'exampleB', + id: '1', + opened: true, + }, +]; + +interface IFields { + content: IDynamicContents[]; + email: string; + termsOfService: boolean; +} + +export interface IReactHookFormProps { + onFormErrors: (errors: FieldErrors) => void; + onFormSubmit: (data: IFields) => void; +} + +export function ReactHookFormDynamicZone( + props: IReactHookFormProps, +): ReactElement { + const { onFormErrors, onFormSubmit } = props; + const { + control, + handleSubmit, + register, + // formState: { errors }, + } = useForm({ + defaultValues: { + content: initialBlocks, + email: '', + termsOfService: false, + }, + }); + const { fields, replace } = useFieldArray({ control, name: 'content' }); + const onValidSubmit: SubmitHandler = (data) => onFormSubmit(data); + const onInvalidSubmit: SubmitErrorHandler = (errors) => + onFormErrors(errors); + + const availableBlocks: IFormDynamicZoneBlock[] = [ + { + block: { + blockHeader: ( + <> + + Example A + + ), + blockType: 'exampleA', + opened: true, + value: '', + }, + button: { + blockType: 'exampleA', + label: 'Example A', + leftSection: , + }, + renderFunc: (b: IExampleBlock, i: number): ReactElement => { + return ( + + + + + ); + }, + }, + { + block: { + blockHeader: ( + <> + + Example B + + ), + blockType: 'exampleB', + opened: true, + selected: '', + }, + button: { + blockType: 'exampleB', + label: 'Example B', + leftSection: , + }, + renderFunc: (b: IExampleBlock, i: number): ReactElement => { + return ( + + ); + }, + }, + ]; + + return ( + +
+ + + availableBlocks={availableBlocks} + blocksArray={fields} + onUpdatedArray={(blocks) => replace(blocks)} + /> + + {/* */} + {/* messages &&*/} + {/* Object.entries(messages).map(([type, message]) => (*/} + {/*

{message}

*/} + {/* ))*/} + {/* }*/} + {/*/ >*/} +
+
+
+ ); +}