From 81571a02351626e2f4ddf714930349091ac15eab Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Fri, 27 Sep 2024 16:42:02 +0200 Subject: [PATCH] feat: add two-step login card (#211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Miłosz Szekiel <12242002+mszekiel@users.noreply.github.com> --- package-lock.json | 540 +++++++++++++++++- .../.vscode/i18n-ally-reviews.yml | 3 + packages/elements-react/.vscode/settings.json | 4 + packages/elements-react/package.json | 17 +- .../card/__tests__/card-two-step.spec.ts | 130 +++++ .../src/components/card/card-two-step.tsx | 344 ++++------- .../components/card/card-two-step.utils.ts | 43 ++ .../src/components/card/index.tsx | 10 +- .../src/components/form/form.tsx | 8 +- .../src/components/form/nodes/input.tsx | 22 +- .../src/components/form/social.tsx | 42 +- .../elements-react/src/context/component.tsx | 2 +- packages/elements-react/src/global.d.ts | 7 +- packages/elements-react/src/locales/de.json | 10 +- packages/elements-react/src/locales/en.json | 10 +- packages/elements-react/src/locales/es.json | 10 +- packages/elements-react/src/locales/fr.json | 10 +- packages/elements-react/src/locales/nl.json | 10 +- packages/elements-react/src/locales/pl.json | 10 +- packages/elements-react/src/locales/pt.json | 10 +- packages/elements-react/src/locales/sv.json | 10 +- .../src/tests/jest/test-utils.tsx | 24 +- .../theme/default/assets/icons/arrow-left.svg | 5 + .../src/theme/default/assets/icons/code.svg | 4 +- .../theme/default/assets/icons/passkey.svg | 4 +- .../theme/default/assets/icons/password.svg | 4 +- .../theme/default/assets/icons/webauthn.svg | 4 +- .../elements-react/src/theme/default/code.svg | 3 - .../default/components/card/auth-methods.tsx | 73 +-- .../theme/default/components/card/badge.tsx | 4 +- .../card/current-identifier-button.tsx | 26 +- .../theme/default/components/form/button.tsx | 4 +- .../default/components/form/checkbox.tsx | 1 - .../theme/default/components/form/input.tsx | 5 +- .../theme/default/components/form/social.tsx | 12 +- .../src/theme/default/flows/login.tsx | 10 +- .../src/theme/default/flows/recovery.tsx | 10 +- .../src/theme/default/flows/registration.tsx | 8 +- .../src/theme/default/flows/settings.tsx | 10 +- .../src/theme/default/flows/verification.tsx | 6 +- .../theme/default/provider-logos/apple.svg | 2 +- .../theme/default/provider-logos/auth0.svg | 2 +- .../theme/default/provider-logos/discord.svg | 4 +- .../theme/default/provider-logos/facebook.svg | 4 +- .../theme/default/provider-logos/generic.svg | 2 +- .../theme/default/provider-logos/github.svg | 2 +- .../theme/default/provider-logos/gitlab.svg | 2 +- .../theme/default/provider-logos/google.svg | 2 +- .../src/theme/default/provider-logos/index.ts | 3 +- .../theme/default/provider-logos/linkedin.svg | 4 +- .../default/provider-logos/microsoft.svg | 2 +- .../theme/default/provider-logos/slack.svg | 2 +- .../theme/default/provider-logos/spotify.svg | 2 +- .../theme/default/provider-logos/yandex.svg | 2 +- packages/elements-react/src/types.ts | 13 +- .../src/util/ui/__test__/ui.spec.ts | 23 + packages/elements-react/src/util/ui/index.ts | 16 + packages/elements-react/tsconfig.json | 3 +- packages/elements-react/tsup.config.ts | 12 +- 59 files changed, 1148 insertions(+), 423 deletions(-) create mode 100644 packages/elements-react/.vscode/i18n-ally-reviews.yml create mode 100644 packages/elements-react/.vscode/settings.json create mode 100644 packages/elements-react/src/components/card/__tests__/card-two-step.spec.ts create mode 100644 packages/elements-react/src/components/card/card-two-step.utils.ts create mode 100644 packages/elements-react/src/theme/default/assets/icons/arrow-left.svg delete mode 100644 packages/elements-react/src/theme/default/code.svg create mode 100644 packages/elements-react/src/util/ui/__test__/ui.spec.ts diff --git a/package-lock.json b/package-lock.json index ff53f0d5f..42d8e5342 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2960,6 +2960,96 @@ "dev": true, "license": "0BSD" }, + "node_modules/@emotion/babel-plugin": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, "node_modules/@emotion/hash": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", @@ -2967,6 +3057,124 @@ "dev": true, "license": "MIT" }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", + "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "dev": true, + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", @@ -3736,6 +3944,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.9.0.tgz", "integrity": "sha512-Ym0trUoC/VO6wQu4YHa0H1VR2tEixFRmwZgADkDLm7nD+vv1Ob+/88mUAoT0pwvirFqYKgUKEwp1tFepqyqvVA==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -3759,6 +3968,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.5.0.tgz", "integrity": "sha512-sg/nR8ILEdUl+2sWu6jc1nQ5s04yucGlH1RVfatW8TSJ5uG3Yy3vgigi8NNC/BuhcncUNPWqSpTCSI1hA+rhiw==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -3770,6 +3980,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz", "integrity": "sha512-6ueQTeJZtwKjmh23bdkq/DMqH4l4bmfvtQH98blOSbiXv/OUiyijSW6jU22IT8BNM1ujCaEvJfTtyCYVH38EMQ==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/intl-localematcher": "0.4.0", @@ -3780,6 +3991,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.0.tgz", "integrity": "sha512-bRTd+rKomvfdS4QDlVJ6TA/Jx1F2h/TBVO5LjvhQ7QPPHp19oPNMIum7W2CMEReq/zPxpmCeB31F9+5gl/qtvw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -3789,12 +4001,14 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, "license": "0BSD" }, "node_modules/@formatjs/intl-listformat": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.4.0.tgz", "integrity": "sha512-ifupb+balZUAF/Oh3QyGRqPRWGSKwWoMPR0cYZEG7r61SimD+m38oFQqVx/3Fp7LfQFF11m7IS+MlxOo2sKINA==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -3806,6 +4020,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz", "integrity": "sha512-6ueQTeJZtwKjmh23bdkq/DMqH4l4bmfvtQH98blOSbiXv/OUiyijSW6jU22IT8BNM1ujCaEvJfTtyCYVH38EMQ==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/intl-localematcher": "0.4.0", @@ -3816,6 +4031,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.0.tgz", "integrity": "sha512-bRTd+rKomvfdS4QDlVJ6TA/Jx1F2h/TBVO5LjvhQ7QPPHp19oPNMIum7W2CMEReq/zPxpmCeB31F9+5gl/qtvw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -3825,6 +4041,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, "license": "0BSD" }, "node_modules/@formatjs/intl-localematcher": { @@ -3848,6 +4065,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz", "integrity": "sha512-6ueQTeJZtwKjmh23bdkq/DMqH4l4bmfvtQH98blOSbiXv/OUiyijSW6jU22IT8BNM1ujCaEvJfTtyCYVH38EMQ==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/intl-localematcher": "0.4.0", @@ -3858,6 +4076,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.0.tgz", "integrity": "sha512-yT6at0qc0DANw9qM/TU8RZaCtfDXtj4pZM/IC2WnVU80yAcliS3KVDiuUt4jSQAeFL9JS5bc2hARnFmjPdA6qw==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -3869,6 +4088,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.0.tgz", "integrity": "sha512-eMmxNpoX/J1IPUjPGSZwo0Wh+7CEvdEMddP2Jxg1gQJXfGfht/FdW2D5XDFj3VMbOTUQlDIdZJY7uC6O6gjPoA==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -3879,6 +4099,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.0.tgz", "integrity": "sha512-bRTd+rKomvfdS4QDlVJ6TA/Jx1F2h/TBVO5LjvhQ7QPPHp19oPNMIum7W2CMEReq/zPxpmCeB31F9+5gl/qtvw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -3888,6 +4109,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, "license": "0BSD" }, "node_modules/@hapi/hoek": { @@ -3907,6 +4129,37 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hookform/devtools": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@hookform/devtools/-/devtools-4.3.1.tgz", + "integrity": "sha512-CrWxEoHQZaOXJZVQ8KBgOuAa8p2LI8M0DAN5GTRTmdCieRwFVjVDEmuTAVazWVRRkpEQSgSt3KYp7VmmqXdEnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/react": "^11.1.5", + "@emotion/styled": "^11.3.0", + "@types/lodash": "^4.14.168", + "little-state-machine": "^4.1.0", + "lodash": "^4.17.21", + "react-simple-animate": "^3.3.12", + "use-deep-compare-effect": "^1.8.1", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/@hookform/devtools/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -19999,6 +20252,21 @@ "bser": "2.1.1" } }, + "node_modules/fdir": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.3.0.tgz", + "integrity": "sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fetch-retry": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-5.0.6.tgz", @@ -20289,6 +20557,13 @@ "node": ">=8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true, + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -21645,6 +21920,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.0.tgz", "integrity": "sha512-AvojYuOaRb6r2veOKfTVpxH9TrmjSdc5iR9R5RgBwrDZYSmAAFVT+QLbW3C4V7Qsg0OguMp67Q/EoUkxZzXRGw==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -21657,6 +21933,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz", "integrity": "sha512-6ueQTeJZtwKjmh23bdkq/DMqH4l4bmfvtQH98blOSbiXv/OUiyijSW6jU22IT8BNM1ujCaEvJfTtyCYVH38EMQ==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/intl-localematcher": "0.4.0", @@ -21667,6 +21944,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.0.tgz", "integrity": "sha512-yT6at0qc0DANw9qM/TU8RZaCtfDXtj4pZM/IC2WnVU80yAcliS3KVDiuUt4jSQAeFL9JS5bc2hARnFmjPdA6qw==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -21678,6 +21956,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.0.tgz", "integrity": "sha512-eMmxNpoX/J1IPUjPGSZwo0Wh+7CEvdEMddP2Jxg1gQJXfGfht/FdW2D5XDFj3VMbOTUQlDIdZJY7uC6O6gjPoA==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -21688,6 +21967,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.0.tgz", "integrity": "sha512-bRTd+rKomvfdS4QDlVJ6TA/Jx1F2h/TBVO5LjvhQ7QPPHp19oPNMIum7W2CMEReq/zPxpmCeB31F9+5gl/qtvw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -21697,6 +21977,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, "license": "0BSD" }, "node_modules/ipaddr.js": { @@ -25321,6 +25602,16 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/little-state-machine": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/little-state-machine/-/little-state-machine-4.8.0.tgz", + "integrity": "sha512-xfi5+iDxTLhu0hbnNubUs+qoQQqxhtEZeObP5ELjUlHnl74bbasY7mOonsGQrAouyrbag3ebNLSse5xX1T7buQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/load-tsconfig": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", @@ -28156,12 +28447,12 @@ "license": "MIT" }, "node_modules/react-hook-form": { - "version": "7.52.1", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.1.tgz", - "integrity": "sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==", + "version": "7.53.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.0.tgz", + "integrity": "sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==", "license": "MIT", "engines": { - "node": ">=12.22.0" + "node": ">=18.0.0" }, "funding": { "type": "opencollective", @@ -28175,6 +28466,7 @@ "version": "6.4.4", "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.4.4.tgz", "integrity": "sha512-/C9Sl/5//ohfkNG6AWlJuf4BhTXsbzyk93K62A4zRhSPANyOGpKZ+fWhN+TLfFd5YjDUHy+exU/09y0w1bO4Xw==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -28202,6 +28494,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz", "integrity": "sha512-6ueQTeJZtwKjmh23bdkq/DMqH4l4bmfvtQH98blOSbiXv/OUiyijSW6jU22IT8BNM1ujCaEvJfTtyCYVH38EMQ==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/intl-localematcher": "0.4.0", @@ -28212,6 +28505,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.0.tgz", "integrity": "sha512-yT6at0qc0DANw9qM/TU8RZaCtfDXtj4pZM/IC2WnVU80yAcliS3KVDiuUt4jSQAeFL9JS5bc2hARnFmjPdA6qw==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -28223,6 +28517,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.0.tgz", "integrity": "sha512-eMmxNpoX/J1IPUjPGSZwo0Wh+7CEvdEMddP2Jxg1gQJXfGfht/FdW2D5XDFj3VMbOTUQlDIdZJY7uC6O6gjPoA==", + "dev": true, "license": "MIT", "dependencies": { "@formatjs/ecma402-abstract": "1.17.0", @@ -28233,6 +28528,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.0.tgz", "integrity": "sha512-bRTd+rKomvfdS4QDlVJ6TA/Jx1F2h/TBVO5LjvhQ7QPPHp19oPNMIum7W2CMEReq/zPxpmCeB31F9+5gl/qtvw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.4.0" @@ -28242,6 +28538,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, "license": "0BSD" }, "node_modules/react-is": { @@ -28293,6 +28590,16 @@ "react-dom": ">=16.8" } }, + "node_modules/react-simple-animate": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/react-simple-animate/-/react-simple-animate-3.5.2.tgz", + "integrity": "sha512-xLE65euP920QMTOmv5haPlml+hmOPDkbIr5WeF7ADIXWBYt5kW/vwpNfWg8EKMab8aeDxIZ6QjffVh8v2dUyhg==", + "dev": true, + "license": "Mit", + "peerDependencies": { + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/react-spa": { "resolved": "examples/react-spa", "link": true @@ -29892,6 +30199,13 @@ } } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "dev": true, + "license": "MIT" + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -30120,9 +30434,9 @@ "license": "BSD-3-Clause" }, "node_modules/tailwind-merge": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.4.0.tgz", - "integrity": "sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz", + "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==", "license": "MIT", "funding": { "type": "github", @@ -30449,6 +30763,33 @@ "dev": true, "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.6.tgz", + "integrity": "sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g==", + "dev": true, + "license": "ISC", + "dependencies": { + "fdir": "^6.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tinyrainbow": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", @@ -31935,6 +32276,24 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-deep-compare-effect": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/use-deep-compare-effect/-/use-deep-compare-effect-1.8.1.tgz", + "integrity": "sha512-kbeNVZ9Zkc0RFGpfMN3MNfaKNvcLNyxOAAd9O4CBZ+kCBXXscn9s/4I+8ytUER4RDpEYs5+O6Rs4PqiZ+rHr5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "dequal": "^2.0.2" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13" + } + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -33492,20 +33851,21 @@ "version": "1.0.0-next.6", "license": "Apache License 2.0", "dependencies": { - "@ory/client-fetch": "1.15.3", + "@ory/client-fetch": "^1.15.4", "clsx": "2.1.1", "input-otp": "1.2.4", - "react-hook-form": "7.52.1", - "react-intl": "6.4.4", - "tailwind-merge": "2.4.0" + "react-hook-form": "7.53.0", + "react-intl": "6.7.0", + "tailwind-merge": "2.5.2" }, "devDependencies": { - "@svgr/plugin-jsx": "^8.1.0", - "esbuild-plugin-svgr": "2.1.0", - "eslint-plugin-react": "7.35.0", + "@hookform/devtools": "^4.3.1", + "@svgr/plugin-svgo": "^8.1.0", + "esbuild-plugin-svgr": "^2.1.0", + "eslint-plugin-react": "7.37.0", "postcss": "8.4.47", "postcss-prefix-selector": "1.16.1", - "tsup": "8.2.3" + "tsup": "8.3.0" }, "peerDependencies": { "react": "18.3.1", @@ -33895,10 +34255,95 @@ "node": ">=18" } }, + "packages/elements-react/node_modules/@formatjs/ecma402-abstract": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", + "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", + "license": "MIT", + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "packages/elements-react/node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", + "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-skeleton-parser": "1.8.2", + "tslib": "^2.4.0" + } + }, + "packages/elements-react/node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz", + "integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "tslib": "^2.4.0" + } + }, + "packages/elements-react/node_modules/@formatjs/intl": { + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.5.tgz", + "integrity": "sha512-f9qPNNgLrh2KvoFvHGIfcPTmNGbyy7lyyV4/P6JioDqtTE7Akdmgt+ZzVndr+yMLZnssUShyTMXxM/6aV9eVuQ==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/fast-memoize": "2.2.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "@formatjs/intl-displaynames": "6.6.8", + "@formatjs/intl-listformat": "7.5.7", + "intl-messageformat": "10.5.14", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "typescript": "^4.7 || 5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/elements-react/node_modules/@formatjs/intl-displaynames": { + "version": "6.6.8", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.6.8.tgz", + "integrity": "sha512-Lgx6n5KxN16B3Pb05z3NLEBQkGoXnGjkTBNCZI+Cn17YjHJ3fhCeEJJUqRlIZmJdmaXQhjcQVDp6WIiNeRYT5g==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "packages/elements-react/node_modules/@formatjs/intl-listformat": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.5.7.tgz", + "integrity": "sha512-MG2TSChQJQT9f7Rlv+eXwUFiG24mKSzmF144PLb8m8OixyXqn4+YWU+5wZracZGCgVTVmx8viCf7IH3QXoiB2g==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "packages/elements-react/node_modules/@formatjs/intl-localematcher": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, "packages/elements-react/node_modules/@ory/client-fetch": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@ory/client-fetch/-/client-fetch-1.15.3.tgz", - "integrity": "sha512-holIdTiVohiEHoAiyb/AlVLicp7ubh/JdhOwSjuZXehfjMWqPmoR0fIPbkRMtE6C6vBbA1Ing9eYW1Hoka+s1g==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/@ory/client-fetch/-/client-fetch-1.15.4.tgz", + "integrity": "sha512-oY5cIuzqoHYaZQKA2N40L76R2RPl2C1RzuNJZFvBxRTtC+hage2ejQI6hBCGfiChkoZ8tTsyI5vErE2KWejFXQ==", "license": "Apache-2.0" }, "packages/elements-react/node_modules/doctrine": { @@ -33955,9 +34400,9 @@ } }, "packages/elements-react/node_modules/eslint-plugin-react": { - "version": "7.35.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", - "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", + "version": "7.37.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.0.tgz", + "integrity": "sha512-IHBePmfWH5lKhJnJ7WB1V+v/GolbB0rjS8XYVCSQCZKaQCAUhMoVoOEn1Ef8Z8Wf0a7l8KTJvuZg5/e4qrZ6nA==", "dev": true, "license": "MIT", "dependencies": { @@ -33987,6 +34432,18 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, + "packages/elements-react/node_modules/intl-messageformat": { + "version": "10.5.14", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz", + "integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/fast-memoize": "2.2.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "tslib": "^2.4.0" + } + }, "packages/elements-react/node_modules/lilconfig": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", @@ -34072,6 +34529,33 @@ } } }, + "packages/elements-react/node_modules/react-intl": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.7.0.tgz", + "integrity": "sha512-f5QhjuKb+WEqiAbL5hDqUs2+sSRkF0vxkTbJ4A8ompt55XTyOHcrDlCXGq4o73ywFFrpgz+78C9IXegSLlya2A==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "@formatjs/intl": "2.10.5", + "@formatjs/intl-displaynames": "6.6.8", + "@formatjs/intl-listformat": "7.5.7", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react": "16 || 17 || 18", + "hoist-non-react-statics": "^3.3.2", + "intl-messageformat": "10.5.14", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "react": "^16.6.0 || 17 || 18", + "typescript": "^4.7 || 5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "packages/elements-react/node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -34149,10 +34633,16 @@ "punycode": "^2.1.0" } }, + "packages/elements-react/node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, "packages/elements-react/node_modules/tsup": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.2.3.tgz", - "integrity": "sha512-6YNT44oUfXRbZuSMNmN36GzwPPIlD2wBccY7looM2fkTcxkf2NEmwr3OZuDZoySklnrIG4hoEtzy8yUXYOqNcg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.3.0.tgz", + "integrity": "sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag==", "dev": true, "license": "MIT", "dependencies": { @@ -34163,7 +34653,6 @@ "debug": "^4.3.5", "esbuild": "^0.23.0", "execa": "^5.1.1", - "globby": "^11.1.0", "joycon": "^3.1.1", "picocolors": "^1.0.1", "postcss-load-config": "^6.0.1", @@ -34171,6 +34660,7 @@ "rollup": "^4.19.0", "source-map": "0.8.0-beta.0", "sucrase": "^3.35.0", + "tinyglobby": "^0.2.1", "tree-kill": "^1.2.2" }, "bin": { diff --git a/packages/elements-react/.vscode/i18n-ally-reviews.yml b/packages/elements-react/.vscode/i18n-ally-reviews.yml new file mode 100644 index 000000000..95de2e1b8 --- /dev/null +++ b/packages/elements-react/.vscode/i18n-ally-reviews.yml @@ -0,0 +1,3 @@ +# Review comments generated by i18n-ally. Please commit this file. + +{} diff --git a/packages/elements-react/.vscode/settings.json b/packages/elements-react/.vscode/settings.json new file mode 100644 index 000000000..46117f440 --- /dev/null +++ b/packages/elements-react/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "i18n-ally.localesPaths": ["src/locales", "src/util/i18n"], + "i18n-ally.keystyle": "flat" +} diff --git a/packages/elements-react/package.json b/packages/elements-react/package.json index 52a82a3c2..0cac7843e 100644 --- a/packages/elements-react/package.json +++ b/packages/elements-react/package.json @@ -28,24 +28,25 @@ "module": "./dist/index.mjs", "types": "./dist/index.d.ts", "dependencies": { - "@ory/client-fetch": "1.15.3", + "@ory/client-fetch": "^1.15.4", "clsx": "2.1.1", "input-otp": "1.2.4", - "react-hook-form": "7.52.1", - "tailwind-merge": "2.4.0", - "react-intl": "6.4.4" + "react-hook-form": "7.53.0", + "react-intl": "6.7.0", + "tailwind-merge": "2.5.2" }, "peerDependencies": { "react": "18.3.1", "react-dom": "18.3.1" }, "devDependencies": { - "@svgr/plugin-jsx": "^8.1.0", - "esbuild-plugin-svgr": "2.1.0", - "eslint-plugin-react": "7.35.0", + "@hookform/devtools": "^4.3.1", + "@svgr/plugin-svgo": "^8.1.0", + "esbuild-plugin-svgr": "^2.1.0", + "eslint-plugin-react": "7.37.0", "postcss": "8.4.47", "postcss-prefix-selector": "1.16.1", - "tsup": "8.2.3" + "tsup": "8.3.0" }, "keywords": [ "ory", diff --git a/packages/elements-react/src/components/card/__tests__/card-two-step.spec.ts b/packages/elements-react/src/components/card/__tests__/card-two-step.spec.ts new file mode 100644 index 000000000..0812d280d --- /dev/null +++ b/packages/elements-react/src/components/card/__tests__/card-two-step.spec.ts @@ -0,0 +1,130 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { + filterZeroStepGroups, + getFinalNodes, + isChoosingMethod, +} from "../card-two-step.utils" +import { UiNode, UiNodeAttributes, UiNodeGroupEnum } from "@ory/client-fetch" + +describe("CardTwoStep/utils", () => { + describe("filterZeroStepGroups", () => { + test("should filter out nodes with group Oidc", () => { + const nodes: UiNode[] = [ + { group: UiNodeGroupEnum.Oidc } as UiNode, + { group: UiNodeGroupEnum.Default } as UiNode, + ] + const result = filterZeroStepGroups(nodes) + expect(result).toHaveLength(1) + expect(result[0].group).toBe(UiNodeGroupEnum.Default) + }) + }) + + describe("isChoosingMethod", () => { + test("should return true if a node has value 'profile:back'", () => { + const uiNodes: UiNode[] = [ + { + attributes: { value: "profile:back" } as UiNodeAttributes, + group: UiNodeGroupEnum.Default, + } as UiNode, + ] + expect(isChoosingMethod(uiNodes)).toBe(true) + }) + + test("should return true if a node is identifier first and hidden", () => { + const uiNodes: UiNode[] = [ + { + attributes: { + name: "identifier", + type: "hidden", + } as UiNodeAttributes, + group: UiNodeGroupEnum.IdentifierFirst, + } as UiNode, + ] + expect(isChoosingMethod(uiNodes)).toBe(true) + }) + + test("should return false if no conditions are met", () => { + const uiNodes: UiNode[] = [ + { + attributes: { name: "other", type: "text" } as UiNodeAttributes, + group: UiNodeGroupEnum.Default, + } as UiNode, + ] + expect(isChoosingMethod(uiNodes)).toBe(false) + }) + }) + + describe("getFinalNodes", () => { + test("should return hidden nodes from identifier_first and default groups, concatenated with selected nodes", () => { + const uniqueGroups = { + identifier_first: [ + { + attributes: { type: "hidden" } as UiNodeAttributes, + } as UiNode, + ], + default: [ + { + attributes: { type: "hidden" } as UiNodeAttributes, + } as UiNode, + ], + } + const selectedGroup = UiNodeGroupEnum.Default + const result = getFinalNodes(uniqueGroups, selectedGroup) + expect(result).toHaveLength(3) + }) + + test("should return only hidden nodes if no group is selected", () => { + const uniqueGroups = { + identifier_first: [ + { + attributes: { type: "hidden" } as UiNodeAttributes, + } as UiNode, + ], + default: [ + { + attributes: { type: "hidden" } as UiNodeAttributes, + } as UiNode, + ], + } + const result = getFinalNodes(uniqueGroups, undefined) + expect(result).toHaveLength(2) + }) + + test("should return an empty array if no hidden nodes are found and no group is selected", () => { + const uniqueGroups = { + identifier_first: [ + { + attributes: { type: "text" } as UiNodeAttributes, + } as UiNode, + ], + default: [ + { + attributes: { type: "text" } as UiNodeAttributes, + } as UiNode, + ], + } + const result = getFinalNodes(uniqueGroups, undefined) + expect(result).toHaveLength(0) + }) + + test("should return selected nodes if no hidden nodes are found", () => { + const uniqueGroups = { + identifier_first: [ + { + attributes: { type: "text" } as UiNodeAttributes, + } as UiNode, + ], + default: [ + { + attributes: { type: "text" } as UiNodeAttributes, + } as UiNode, + ], + } + const selectedGroup = UiNodeGroupEnum.Default + const result = getFinalNodes(uniqueGroups, selectedGroup) + expect(result).toHaveLength(1) + }) + }) +}) diff --git a/packages/elements-react/src/components/card/card-two-step.tsx b/packages/elements-react/src/components/card/card-two-step.tsx index 38b1c81bf..396ce4e24 100644 --- a/packages/elements-react/src/components/card/card-two-step.tsx +++ b/packages/elements-react/src/components/card/card-two-step.tsx @@ -1,260 +1,111 @@ -import { OryCardHeader } from "./header" +import { + FlowType, + UiNode, + UiNodeGroupEnum, + UiNodeInputAttributes, +} from "@ory/client-fetch" +import { useState } from "react" +import { OryCard, OryCardContent, OryCardFooter } from "." +import { useComponents, useNodeSorter, useOryFlow } from "../../context" +import { useNodesGroups } from "../../util/ui" import { OryForm } from "../form/form" import { OryCardValidationMessages } from "../form/messages" import { Node } from "../form/nodes/node" -import { OryFormSocialButtons } from "../form/social" -import { useComponents, useNodeSorter } from "../../context" -import { useOryFlow } from "../../context" +import { OryFormSocialButtonsForm } from "../form/social" +import { OryCardHeader } from "./header" import { - isUiNodeInputAttributes, - UiNode, - UiNodeInputAttributesNodeTypeEnum, - UiNodeInputAttributesTypeEnum, - UiNodeTypeEnum, - UiTextTypeEnum, -} from "@ory/client-fetch" -import { Dispatch, useEffect, useState } from "react" -import { OryCard, OryCardContent, OryCardFooter, OryCardProps } from "." - -type ExtendedUiNode = UiNode & { twoStepContinue?: boolean } + filterZeroStepGroups, + getFinalNodes, + isChoosingMethod, +} from "./card-two-step.utils" -const nodeContinue: ExtendedUiNode = { - attributes: { - label: { - id: 1040003, - text: "Continue", - type: UiTextTypeEnum.Info, - }, - name: "two_step_continue", - disabled: false, - node_type: UiNodeInputAttributesNodeTypeEnum.Input, - type: UiNodeInputAttributesTypeEnum.Submit, - value: "Continue", - }, - group: "default", - messages: [], - meta: {}, - type: UiNodeTypeEnum.Input, - twoStepContinue: true, -} - -const nodePickMethod: ExtendedUiNode = { - attributes: { - label: { - id: 1040003111, - text: "Try another method", - type: UiTextTypeEnum.Info, - }, - name: "two_step_select", - disabled: false, - node_type: UiNodeInputAttributesNodeTypeEnum.Input, - type: UiNodeInputAttributesTypeEnum.Submit, - value: "Try another method", - }, - group: "default", - messages: [], - meta: {}, - type: UiNodeTypeEnum.Input, - twoStepContinue: true, -} -const nodeGoBack: ExtendedUiNode = { - attributes: { - label: { - id: 1040008, - text: "Back", - type: UiTextTypeEnum.Info, - }, - name: "two_step_back", - disabled: false, - node_type: UiNodeInputAttributesNodeTypeEnum.Input, - type: UiNodeInputAttributesTypeEnum.Submit, - value: "Back", - }, - group: "default", - messages: [], - meta: {}, - type: UiNodeTypeEnum.Input, - twoStepContinue: true, +enum ProcessStep { + ProvideIdentifier, + ChooseAuthMethod, + ExecuteAuthMethod, } -type OptionProps = { - setGroups: Dispatch> - setStep: Dispatch> - title: string - group: string - description: string -} +export function OryTwoStepCard() { + const { + flow: { ui }, + config, + } = useOryFlow() -export function Option({ - setGroups, - setStep, - title, - group, - description, -}: OptionProps) { - return ( -
{ - setGroups([group]) - setStep(2) - }} - > -
- - - -
-
-
{title}
-
{description}
-
-
- ) -} + const choosingMethod = isChoosingMethod(ui.nodes) -export function OryTwoStepCard({ children }: OryCardProps) { - const [step, setStep] = useState(-1) - const [groups, setGroups] = useState([]) + const [selectedGroup, setSelectedGroup] = useState< + UiNodeGroupEnum | undefined + >() const Components = useComponents() const { FormGroup } = useComponents() const { flowType } = useOryFlow() - const { - flow: { ui }, - } = useOryFlow() - let nodes: (UiNode & { twoStepContinue?: boolean })[] = ui.nodes - const nodeSorter = useNodeSorter() const sortNodes = (a: UiNode, b: UiNode) => nodeSorter(a, b, { flowType }) - // If we have multiple auth methods, we show two-step login. For this we need at least two auth methods. - // Social sign in / OpenID Connect does not count, as no user input apart from a click is required. - const hasMultiple = - nodes.filter(({ group }) => group === "default" || group === "oidc") - .length > 2 + const uniqueGroups = useNodesGroups(ui.nodes) - useEffect(() => { - setStep(0) - }, []) - - if (children) { - return {children} - } - - if (!hasMultiple) { - return ( - - - - - + const options: UiNodeGroupEnum[] = Object.values(UiNodeGroupEnum) + .filter((group) => uniqueGroups[group]?.length) + .filter( + (group) => + !( + [ + UiNodeGroupEnum.Oidc, + UiNodeGroupEnum.Default, + UiNodeGroupEnum.IdentifierFirst, + UiNodeGroupEnum.Profile, + ] as UiNodeGroupEnum[] + ).includes(group), ) - } - const options: (OptionProps & { show: boolean })[] = [ - { - title: "Passkey", - group: "passkey", - description: "Use your fingerprint or face to sign in.", - setStep: () => setStep(2), - setGroups: () => setGroups(["passkey"]), - show: nodes.findIndex(({ group }) => group === "passkey") !== -1, - }, - { - title: "Code", - group: "code", - description: "Enter a code from your authenticator app.", - setStep: () => setStep(2), - setGroups: () => setGroups(["code"]), - show: nodes.findIndex(({ group }) => group === "code") !== -1, - }, - { - title: "Password", - group: "password", - description: "Enter your password.", - setStep: () => setStep(2), - setGroups: () => setGroups(["password"]), - show: nodes.findIndex(({ group }) => group === "password") !== -1, - }, - { - title: "WebAuthn", - group: "webauthn", - description: "Use a security key to sign in.", - setStep: () => setStep(2), - setGroups: () => setGroups(["webauthn"]), - show: nodes.findIndex(({ group }) => group === "webauthn") !== -1, - }, - ] + const hasOIDC = Boolean(uniqueGroups.oidc?.length) - switch (step) { - case -1: - nodes = nodes.sort(sortNodes) - break - case 0: - nodes = nodes - .filter(({ group }) => ["default"].includes(group)) - .sort(sortNodes) - nodes = [...nodes, nodeContinue] - break - case 1: - return ( - - - - {options.map((props, k) => ( - - ))} - - - - ) - case 2: - nodes = nodes - .filter(({ group }) => groups.includes(group)) - .sort(sortNodes) - nodes = [...nodes, nodeGoBack, nodePickMethod] - break - } + const zeroStepGroups = filterZeroStepGroups(ui.nodes) + const finalNodes = getFinalNodes(uniqueGroups, selectedGroup) + + const step = selectedGroup + ? ProcessStep.ExecuteAuthMethod + : choosingMethod + ? ProcessStep.ChooseAuthMethod + : ProcessStep.ProvideIdentifier return ( + {step === ProcessStep.ProvideIdentifier && hasOIDC && ( + + )} - {step === 0 && } - {nodes.sort(sortNodes).map((node, k) => { - if (node.twoStepContinue) { - if (isUiNodeInputAttributes(node.attributes)) { - return ( - { - setStep(step + 1) - }} - /> - ) - } - } - return - })} + {step === ProcessStep.ProvideIdentifier && + zeroStepGroups + .sort(sortNodes) + .map((node, k) => )} + {step === ProcessStep.ChooseAuthMethod && ( + <> + {flowType === FlowType.Login && ( + + )} + {options.map((option) => ( + setSelectedGroup(option)} + /> + ))} + + )} + {step === ProcessStep.ExecuteAuthMethod && ( + <> + setSelectedGroup(undefined)} /> + {finalNodes.sort(sortNodes).map((node, k) => ( + + ))} + + )} @@ -262,3 +113,38 @@ export function OryTwoStepCard({ children }: OryCardProps) { ) } + +type BackButtonProps = { + onClick?: () => void + href?: string +} + +const BackButton = ({ onClick, href }: BackButtonProps) => { + const { + flow: { ui }, + } = useOryFlow() + const Components = useComponents() + + const nodeBackButton = ui.nodes.find( + (node) => + // ("value" in node.attributes && + // node.attributes.value === "profile:back") || + "name" in node.attributes && + node.attributes.name === "identifier" && + node.group === "identifier_first", + ) + + if (!nodeBackButton) { + return null + } + + return ( + + ) +} diff --git a/packages/elements-react/src/components/card/card-two-step.utils.ts b/packages/elements-react/src/components/card/card-two-step.utils.ts new file mode 100644 index 000000000..f948ca141 --- /dev/null +++ b/packages/elements-react/src/components/card/card-two-step.utils.ts @@ -0,0 +1,43 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import { UiNode, UiNodeGroupEnum } from "@ory/client-fetch" + +export function isChoosingMethod(uiNodes: UiNode[]): boolean { + return ( + uiNodes.some( + (node) => + "value" in node.attributes && node.attributes.value === "profile:back", + ) || + uiNodes.some( + (node) => + node.group === UiNodeGroupEnum.IdentifierFirst && + "name" in node.attributes && + node.attributes.name === "identifier" && + node.attributes.type === "hidden", + ) + ) +} + +export function filterZeroStepGroups(nodes: UiNode[]): UiNode[] { + return nodes.filter((node) => node.group !== UiNodeGroupEnum.Oidc) +} + +export function getFinalNodes( + uniqueGroups: Partial>, + selectedGroup: UiNodeGroupEnum | undefined, +): UiNode[] { + const selectedNodes: UiNode[] = selectedGroup + ? (uniqueGroups[selectedGroup] ?? []) + : [] + + return [ + ...(uniqueGroups?.identifier_first ?? []), + ...(uniqueGroups?.default ?? []), + ] + .flat() + .filter( + (node) => "type" in node.attributes && node.attributes.type === "hidden", + ) + .concat(selectedNodes) +} diff --git a/packages/elements-react/src/components/card/index.tsx b/packages/elements-react/src/components/card/index.tsx index cb15fe3dc..c49140c08 100644 --- a/packages/elements-react/src/components/card/index.tsx +++ b/packages/elements-react/src/components/card/index.tsx @@ -1,9 +1,9 @@ +import { ComponentType, PropsWithChildren } from "react" +import { useComponents } from "../../context" import { OryForm } from "../form/form" import { OryFormGroups } from "../form/groups" import { OryCardValidationMessages } from "../form/messages" -import { OryFormSocialButtons } from "../form/social" -import { useComponents } from "../../context" -import { ComponentType, PropsWithChildren } from "react" +import { OryTwoStepCard } from "./card-two-step" import { OryCardHeader, OryCardHeaderProps } from "./header" export type OryCardContentProps = PropsWithChildren @@ -19,7 +19,6 @@ export function OryCardContent({ children }: OryCardContentProps) { - {children} } @@ -91,6 +91,6 @@ export type OryCardComponents = { CardLogo: ComponentType } -export { OryCardHeader } +export { OryCardHeader, OryTwoStepCard } export type { OryCardHeaderProps } diff --git a/packages/elements-react/src/components/form/form.tsx b/packages/elements-react/src/components/form/form.tsx index 79d771cd4..b5507d4a8 100644 --- a/packages/elements-react/src/components/form/form.tsx +++ b/packages/elements-react/src/components/form/form.tsx @@ -13,6 +13,7 @@ import { FormValues, HeadlessAuthMethodListItemProps, HeadlessButtonProps, + HeadlessCurrentIdentifierProps, HeadlessFormProps, HeadlessImageProps, HeadlessInputProps, @@ -69,7 +70,7 @@ export type OryFormComponents = { MessageContainer: ComponentType Message: ComponentType - CurrentIdentifierButton: ComponentType + CurrentIdentifierButton: ComponentType } export type OryFormProps = PropsWithChildren @@ -77,7 +78,6 @@ export type OryFormProps = PropsWithChildren export function OryForm({ children }: OryFormProps) { const { FormContainer } = useComponents() const flowContainer = useOryFlow() - const methods = useForm({ // TODO: Generify this, so we have typesafety in the submit handler. defaultValues: computeDefaultValues(flowContainer), @@ -109,6 +109,7 @@ export function OryForm({ children }: OryFormProps) { if (submitData.method === "code" && data.code) { submitData.resend = "" } + console.log(submitData) await onSubmitLogin(flowContainer, { onRedirect, setFlowContainer: handleSuccess, @@ -120,10 +121,11 @@ export function OryForm({ children }: OryFormProps) { const submitData: UpdateRegistrationFlowBody = { ...(data as unknown as UpdateRegistrationFlowBody), } + if (submitData.method === "code" && submitData.code) { submitData.resend = "" } - console + await onSubmitRegistration(flowContainer, { onRedirect, setFlowContainer: handleSuccess, diff --git a/packages/elements-react/src/components/form/nodes/input.tsx b/packages/elements-react/src/components/form/nodes/input.tsx index 96d578451..b7c56df3e 100644 --- a/packages/elements-react/src/components/form/nodes/input.tsx +++ b/packages/elements-react/src/components/form/nodes/input.tsx @@ -51,10 +51,6 @@ export const NodeInput = ({ const isPinCodeInput = (attrs.name === "code" && node.group === "code") || (attrs.name === "totp_code" && node.group === "totp") - const isCurrentIdentifier = - attrs.name == "identifier" && - node.group === "identifier_first" && - attrs.type === "hidden" const isResend = attrs.name === "resend" && node.group === "code" switch (nodeType) { @@ -86,19 +82,11 @@ export const NodeInput = ({ ) case UiNodeInputAttributesTypeEnum.Hidden: return ( - <> - {isCurrentIdentifier && ( - - )} - - + ) default: if (isPinCodeInput) { diff --git a/packages/elements-react/src/components/form/social.tsx b/packages/elements-react/src/components/form/social.tsx index e145d0bfc..60e106e6a 100644 --- a/packages/elements-react/src/components/form/social.tsx +++ b/packages/elements-react/src/components/form/social.tsx @@ -2,7 +2,8 @@ import { useComponents } from "../../context" import { useOryFlow } from "../../context" import { UiNode, UiNodeInputAttributes } from "@ory/client-fetch" import { PropsWithChildren } from "react" -import { Node } from "./nodes/node" +import { OryForm } from "./form" +import { useFormContext } from "react-hook-form" export type HeadlessSocialButtonsProps = PropsWithChildren<{ hideDivider?: boolean @@ -15,6 +16,7 @@ export type HeadlessSocialButtonContainerProps = PropsWithChildren<{ export type HeadlessSocialButtonProps = PropsWithChildren<{ node: UiNode attributes: UiNodeInputAttributes + onClick?: () => void }> export function OryFormSocialButtons({ @@ -24,11 +26,13 @@ export function OryFormSocialButtons({ const { flow: { ui }, } = useOryFlow() + const { setValue } = useFormContext() // Only get the oidc nodes. const filteredNodes = ui.nodes.filter((node) => node.group === "oidc") - const { SocialButtonContainer, HorizontalDivider } = useComponents() + const { SocialButtonContainer, HorizontalDivider, SocialButton } = + useComponents() if (filteredNodes.length === 0) { return null @@ -44,7 +48,20 @@ export function OryFormSocialButtons({ {children ?? filteredNodes.map((node, k) => { - return + return ( + { + setValue( + "provider", + (node.attributes as UiNodeInputAttributes).value, + ) + setValue("method", "oidc") + }} + /> + ) })} {!hideDivider && filteredNodes.length > 0 && otherNodes.length > 0 && ( @@ -53,3 +70,22 @@ export function OryFormSocialButtons({ ) } + +export function OryFormSocialButtonsForm() { + const { + flow: { ui }, + } = useOryFlow() + + // Only get the oidc nodes. + const filteredNodes = ui.nodes.filter((node) => node.group === "oidc") + + if (filteredNodes.length === 0) { + return null + } + + return ( + + + + ) +} diff --git a/packages/elements-react/src/context/component.tsx b/packages/elements-react/src/context/component.tsx index 8aac5e404..70b49167f 100644 --- a/packages/elements-react/src/context/component.tsx +++ b/packages/elements-react/src/context/component.tsx @@ -30,8 +30,8 @@ export function useNodeSorter() { const defaultGroupOrder = [ "oidc", - "default", "identifier_first", + "default", "profile", "password", "passkey", diff --git a/packages/elements-react/src/global.d.ts b/packages/elements-react/src/global.d.ts index 107f92381..04d3e9566 100644 --- a/packages/elements-react/src/global.d.ts +++ b/packages/elements-react/src/global.d.ts @@ -1,7 +1,12 @@ // Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 + declare module "*.svg" { - const ReactComponent: React.FC> + import * as React from "react" + + const ReactComponent: React.FunctionComponent< + React.ComponentProps<"svg"> & { size?: number } + > export default ReactComponent } diff --git a/packages/elements-react/src/locales/de.json b/packages/elements-react/src/locales/de.json index 25f164440..5f23dbeca 100644 --- a/packages/elements-react/src/locales/de.json +++ b/packages/elements-react/src/locales/de.json @@ -172,5 +172,13 @@ "verification.registration-button": "Registrieren", "verification.registration-label": "Sie haben noch kein Konto?", "verification.title": "Verifizieren Sie ihr Konto", - "verification.back-button": "Zurück" + "verification.back-button": "Zurück", + "two-step.code.description": "Ein Bestätigungscode wird an Ihre E-Mail gesendet.", + "two-step.code.title": "E-Mail-Code", + "two-step.passkey.description": "Verwenden Sie die Fingerabdruck- oder Gesichtserkennung Ihres Geräts", + "two-step.passkey.title": "Passwort (empfohlen)", + "two-step.password.description": "Geben Sie Ihr Passwort ein, das mit Ihrem Konto verknüpft ist", + "two-step.password.title": "Passwort", + "two-step.webauthn.description": "Verwenden Sie Ihren Sicherheitsschlüssel zur Authentifizierung", + "two-step.webauthn.title": "Sicherheitsschlüssel" } diff --git a/packages/elements-react/src/locales/en.json b/packages/elements-react/src/locales/en.json index ccdcb74e1..861d360df 100644 --- a/packages/elements-react/src/locales/en.json +++ b/packages/elements-react/src/locales/en.json @@ -172,5 +172,13 @@ "verification.registration-button": "Sign up", "verification.registration-label": "Don't have an account?", "verification.title": "Verify your account", - "verification.back-button": "Back" + "verification.back-button": "Back", + "two-step.password.title": "Password", + "two-step.password.description": "Enter your password associated with your account", + "two-step.code.title": "Email code", + "two-step.code.description": "A verification code will be sent to your email", + "two-step.webauthn.title": "Security Key", + "two-step.webauthn.description": "Use your security key to authenticate", + "two-step.passkey.title": "Passkey (recommended)", + "two-step.passkey.description": "Use your device's for fingerprint or face recognition" } diff --git a/packages/elements-react/src/locales/es.json b/packages/elements-react/src/locales/es.json index 9a291255a..d1b5e8334 100644 --- a/packages/elements-react/src/locales/es.json +++ b/packages/elements-react/src/locales/es.json @@ -172,5 +172,13 @@ "verification.registration-button": "Registrarse", "verification.registration-label": "¿No tiene una cuenta?", "verification.title": "Verificar su cuenta", - "verification.back-button": "Regresar" + "verification.back-button": "Regresar", + "two-step.code.description": "Se enviará un código de verificación a tu correo electrónico.", + "two-step.code.title": "Código de correo electrónico", + "two-step.passkey.description": "Utiliza el reconocimiento de huellas dactilares o facial de tu dispositivo.", + "two-step.passkey.title": "Clave de acceso (recomendada)", + "two-step.password.description": "Ingrese la contraseña asociada con su cuenta", + "two-step.password.title": "Contraseña", + "two-step.webauthn.description": "Utiliza tu llave de seguridad para autenticarte", + "two-step.webauthn.title": "Clave de Seguridad" } diff --git a/packages/elements-react/src/locales/fr.json b/packages/elements-react/src/locales/fr.json index b4b8c986e..e0d9851d3 100644 --- a/packages/elements-react/src/locales/fr.json +++ b/packages/elements-react/src/locales/fr.json @@ -172,5 +172,13 @@ "verification.registration-button": "S'inscrire", "verification.registration-label": "Vous n'avez pas de compte ?", "verification.title": "Vérifiez votre compte", - "verification.back-button": "Revenir en arrière" + "verification.back-button": "Revenir en arrière", + "two-step.code.description": "Un code de vérification sera envoyé à votre email", + "two-step.code.title": "Code de courrier électronique", + "two-step.passkey.description": "Utilisez l'appareil pour la reconnaissance d'empreintes digitales ou de visage", + "two-step.passkey.title": "Clé de passe (recommandée)", + "two-step.password.description": "Entrez votre mot de passe associé à votre compte", + "two-step.password.title": "Mot de passe", + "two-step.webauthn.description": "Utilisez votre clé de sécurité pour vous authentifier", + "two-step.webauthn.title": "Clé de Sécurité" } diff --git a/packages/elements-react/src/locales/nl.json b/packages/elements-react/src/locales/nl.json index b4bc597d2..0e9cf478d 100644 --- a/packages/elements-react/src/locales/nl.json +++ b/packages/elements-react/src/locales/nl.json @@ -172,5 +172,13 @@ "verification.registration-button": "Registreren", "verification.registration-label": "Heb je nog geen account?", "verification.title": "Verifieer je account", - "verification.back-button": "Ga terug" + "verification.back-button": "Ga terug", + "two-step.code.description": "Een verificatiecode wordt naar uw e-mail gestuurd", + "two-step.code.title": "E-mailcode", + "two-step.passkey.description": "Gebruik de vingerafdruk- of gezichtsherkenning van uw apparaat", + "two-step.passkey.title": "Toegangscode (aanbevolen)", + "two-step.password.description": "Voer uw wachtwoord in dat is gekoppeld aan uw account", + "two-step.password.title": "Wachtwoord", + "two-step.webauthn.description": "Gebruik uw beveiligingssleutel om te verifiëren", + "two-step.webauthn.title": "Beveiligingssleutel" } diff --git a/packages/elements-react/src/locales/pl.json b/packages/elements-react/src/locales/pl.json index ed28ec246..4b1b116b3 100644 --- a/packages/elements-react/src/locales/pl.json +++ b/packages/elements-react/src/locales/pl.json @@ -172,5 +172,13 @@ "verification.registration-button": "Zarejestruj się", "verification.registration-label": "Nie posiadasz konta?", "verification.title": "Zweryfikuj konto", - "verification.back-button": "Cofnij" + "verification.back-button": "Cofnij", + "two-step.code.description": "Kod weryfikacyjny zostanie wysłany na Twój adres email.", + "two-step.code.title": "Kod email", + "two-step.passkey.description": "Użyj swojego urządzenia lub funkcji rozpoznawania twarzy na swoim urządzeniu.", + "two-step.passkey.title": "Klucz dostępu (zalecany)", + "two-step.password.description": "Wprowadź hasło powiązane z twoim kontem", + "two-step.password.title": "Hasło", + "two-step.webauthn.description": "Użyj swojego klucza bezpieczeństwa do uwierzytelnienia", + "two-step.webauthn.title": "Klucz bezpieczeństwa" } diff --git a/packages/elements-react/src/locales/pt.json b/packages/elements-react/src/locales/pt.json index 1720acfa3..483ef71ec 100644 --- a/packages/elements-react/src/locales/pt.json +++ b/packages/elements-react/src/locales/pt.json @@ -172,5 +172,13 @@ "verification.registration-button": "Registar", "verification.registration-label": "Não tem uma conta?", "verification.title": "Verifique a sua conta", - "verification.back-button": "Voltar" + "verification.back-button": "Voltar", + "two-step.code.description": "Um código de verificação será enviado para o seu email", + "two-step.code.title": "Código de email", + "two-step.passkey.description": "Use o seu dispositivo para reconhecimento de impressão digital ou facial.", + "two-step.passkey.title": "Chave de acesso (recomendado)", + "two-step.password.description": "Insira a sua senha associada à sua conta", + "two-step.password.title": "Senha", + "two-step.webauthn.description": "Use sua chave de segurança para autenticar", + "two-step.webauthn.title": "Chave de Segurança" } diff --git a/packages/elements-react/src/locales/sv.json b/packages/elements-react/src/locales/sv.json index c5c8a28bb..2391c4216 100644 --- a/packages/elements-react/src/locales/sv.json +++ b/packages/elements-react/src/locales/sv.json @@ -172,5 +172,13 @@ "verification.registration-button": "Skapa konto", "verification.registration-label": "Har du inget konto?", "verification.title": "Verifiera ditt konto", - "verification.back-button": "Tillbaka" + "verification.back-button": "Tillbaka", + "two-step.code.description": "En verifieringskod kommer att skickas till din e-post", + "two-step.code.title": "E-postkod", + "two-step.passkey.description": "Använd din enhets fingeravtryck eller ansiktsigenkänning", + "two-step.passkey.title": "Passerkod (rekommenderad)", + "two-step.password.description": "Ange ditt lösenord kopplat till ditt konto", + "two-step.password.title": "Lösenord", + "two-step.webauthn.description": "Använd din säkerhetsnyckel för att autentisera", + "two-step.webauthn.title": "Säkerhetsnyckel" } diff --git a/packages/elements-react/src/tests/jest/test-utils.tsx b/packages/elements-react/src/tests/jest/test-utils.tsx index e61f0668c..0b8d1314e 100644 --- a/packages/elements-react/src/tests/jest/test-utils.tsx +++ b/packages/elements-react/src/tests/jest/test-utils.tsx @@ -1,5 +1,10 @@ -import { PropsWithChildren, ReactElement } from "react" -import { OryComponentProvider } from "../../context" +import { PropsWithChildren, ReactElement, ReactNode } from "react" +import { + OryComponentProvider, + OryProvider, + ProviderProps, + SupportedTranslations, +} from "../../context" import { OryDefaultComponents } from "../../theme/default" import { render, RenderOptions } from "@testing-library/react" import { OryClientConfiguration } from "../../util" @@ -31,5 +36,20 @@ export const defaultConfiguration: OryClientConfiguration = { }, } +export function renderWithOryProvider( + ui: ReactNode, + { + providerProps, + ...renderOptions + }: RenderOptions & { providerProps: ProviderProps }, +) { + return render(ui, { + wrapper: ({ children }) => ( + {children} + ), + ...renderOptions, + }) +} + export * from "@testing-library/react" export { customRender as render } diff --git a/packages/elements-react/src/theme/default/assets/icons/arrow-left.svg b/packages/elements-react/src/theme/default/assets/icons/arrow-left.svg new file mode 100644 index 000000000..656c0397f --- /dev/null +++ b/packages/elements-react/src/theme/default/assets/icons/arrow-left.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/elements-react/src/theme/default/assets/icons/code.svg b/packages/elements-react/src/theme/default/assets/icons/code.svg index ac19b91cd..2e775f725 100644 --- a/packages/elements-react/src/theme/default/assets/icons/code.svg +++ b/packages/elements-react/src/theme/default/assets/icons/code.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/elements-react/src/theme/default/assets/icons/passkey.svg b/packages/elements-react/src/theme/default/assets/icons/passkey.svg index ede8307bf..bf19bc848 100644 --- a/packages/elements-react/src/theme/default/assets/icons/passkey.svg +++ b/packages/elements-react/src/theme/default/assets/icons/passkey.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/elements-react/src/theme/default/assets/icons/password.svg b/packages/elements-react/src/theme/default/assets/icons/password.svg index d9ce74524..05b349ad3 100644 --- a/packages/elements-react/src/theme/default/assets/icons/password.svg +++ b/packages/elements-react/src/theme/default/assets/icons/password.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/elements-react/src/theme/default/assets/icons/webauthn.svg b/packages/elements-react/src/theme/default/assets/icons/webauthn.svg index 3dd14f381..4a69fa0fe 100644 --- a/packages/elements-react/src/theme/default/assets/icons/webauthn.svg +++ b/packages/elements-react/src/theme/default/assets/icons/webauthn.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/elements-react/src/theme/default/code.svg b/packages/elements-react/src/theme/default/code.svg deleted file mode 100644 index ac19b91cd..000000000 --- a/packages/elements-react/src/theme/default/code.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/elements-react/src/theme/default/components/card/auth-methods.tsx b/packages/elements-react/src/theme/default/components/card/auth-methods.tsx index 9e5129f99..7b6fd6219 100644 --- a/packages/elements-react/src/theme/default/components/card/auth-methods.tsx +++ b/packages/elements-react/src/theme/default/components/card/auth-methods.tsx @@ -1,61 +1,44 @@ import { HeadlessAuthMethodListItemProps } from "@ory/elements-react" -import { FunctionComponent, SVGAttributes } from "react" import code from "../../assets/icons/code.svg" import passkey from "../../assets/icons/passkey.svg" import password from "../../assets/icons/password.svg" import webauthn from "../../assets/icons/webauthn.svg" +import { useIntl } from "react-intl" + +const iconsMap: Record = { + code, + passkey, + password, + webauthn, +} // TODO: create a next specific component with Image for this export function DefaultAuthMethodListItem({ - setGroups, - setStep, + onClick, group, }: HeadlessAuthMethodListItemProps) { - let Icon: FunctionComponent> | null = null - let title = "" - let description = "" - - switch (group) { - case "passkey": - Icon = passkey - title = "Passkey" - description = "Use your fingerprint or face to sign in." - break - case "password": - Icon = password - title = "Password" - description = "Use your password to sign in." - break - case "webauthn": - Icon = webauthn - title = "Security Key" - description = "Use a security key to sign in." - break - case "code": - Icon = code - title = "Email" - description = "Enter a code sent to your email." - break - } + const intl = useIntl() + const Icon = iconsMap[group] || null return ( -
{ - setGroups([group]) - setStep(2) - }} - > -
- {Icon && } -
-
-
{title}
-
{description}
-
+
+
) } diff --git a/packages/elements-react/src/theme/default/components/card/badge.tsx b/packages/elements-react/src/theme/default/components/card/badge.tsx index d2c7cb18c..7f87b8b4e 100644 --- a/packages/elements-react/src/theme/default/components/card/badge.tsx +++ b/packages/elements-react/src/theme/default/components/card/badge.tsx @@ -4,8 +4,8 @@ import OryLogoVertical from "../../assets/ory-badge-vertical.svg" export function Badge() { return (
- - + +
) } diff --git a/packages/elements-react/src/theme/default/components/card/current-identifier-button.tsx b/packages/elements-react/src/theme/default/components/card/current-identifier-button.tsx index f86b2ca1c..bb360a08b 100644 --- a/packages/elements-react/src/theme/default/components/card/current-identifier-button.tsx +++ b/packages/elements-react/src/theme/default/components/card/current-identifier-button.tsx @@ -1,18 +1,28 @@ -import { HeadlessButtonProps } from "@ory/elements-react" -import { DefaultInput } from "../form/input" +import { HeadlessCurrentIdentifierProps } from "@ory/elements-react" +import IconArrowLeft from "../../assets/icons/arrow-left.svg" export function DefaultCurrentIdentifierButton({ attributes, - node, -}: HeadlessButtonProps) { + onClick, + type, + href, +}: HeadlessCurrentIdentifierProps) { + const Element = onClick ? "button" : "a" + return (
- - + + + {attributes.value} - - +
) } diff --git a/packages/elements-react/src/theme/default/components/form/button.tsx b/packages/elements-react/src/theme/default/components/form/button.tsx index b1517f20d..c8af0e273 100644 --- a/packages/elements-react/src/theme/default/components/form/button.tsx +++ b/packages/elements-react/src/theme/default/components/form/button.tsx @@ -52,9 +52,7 @@ export const DefaultButton = ({ } }} className={cn( - // TODO: Difficult to resolve merge conflict here. Please ensure this is correct: - // "relative antialiased rounded border gap-3 leading-none transition-colors ease-linear duration-100 px-4 py-4.5 text-sm font-medium", - "antialiased rounded-border-radius-buttons border border-transparent gap-3 bg-button-primary-bg-default hover:bg-button-primary-bg-hover transition-colors text-button-primary-fg-default hover:text-button-primary-fg-hover px-4 py-4.5 text-sm leading-none font-medium", + "antialiased rounded-border-radius-buttons border border-transparent gap-3 bg-button-primary-bg-default hover:bg-button-primary-bg-hover transition-colors text-button-primary-fg-default hover:text-button-primary-fg-hover px-4 py-3 md:py-4.5 text-sm leading-none font-medium", { "cursor-not-allowed": isSubmitting, "bg-button-primary-bg-hover": isSubmitting, diff --git a/packages/elements-react/src/theme/default/components/form/checkbox.tsx b/packages/elements-react/src/theme/default/components/form/checkbox.tsx index 025f58283..653e2e4a9 100644 --- a/packages/elements-react/src/theme/default/components/form/checkbox.tsx +++ b/packages/elements-react/src/theme/default/components/form/checkbox.tsx @@ -60,7 +60,6 @@ export const DefaultCheckbox = ({
{ const label = getNodeLabel(node) const { register } = useFormContext() - const { value, autocomplete, name, ...rest } = attributes + const { value, autocomplete, name, maxlength, ...rest } = attributes return ( {Logo ? ( diff --git a/packages/elements-react/src/theme/default/flows/login.tsx b/packages/elements-react/src/theme/default/flows/login.tsx index 1e43f2ed6..aea7b03f0 100644 --- a/packages/elements-react/src/theme/default/flows/login.tsx +++ b/packages/elements-react/src/theme/default/flows/login.tsx @@ -1,13 +1,13 @@ "use client" import { FlowType, LoginFlow } from "@ory/client-fetch" -import { PropsWithChildren } from "react" -import { OryDefaultComponents } from "../components" import { - OryFlowComponents, - OryCard, OryClientConfiguration, + OryFlowComponents, OryProvider, + OryTwoStepCard, } from "@ory/elements-react" +import { PropsWithChildren } from "react" +import { OryDefaultComponents } from "../components" export type LoginFlowContextProps = { flow: LoginFlow @@ -32,7 +32,7 @@ export function Login({ flowType={FlowType.Login} components={components} > - {children ?? } + {children ?? } ) } diff --git a/packages/elements-react/src/theme/default/flows/recovery.tsx b/packages/elements-react/src/theme/default/flows/recovery.tsx index 41e688c81..ff95b8e88 100644 --- a/packages/elements-react/src/theme/default/flows/recovery.tsx +++ b/packages/elements-react/src/theme/default/flows/recovery.tsx @@ -1,13 +1,13 @@ "use client" import { FlowType, RecoveryFlow } from "@ory/client-fetch" -import { PropsWithChildren } from "react" -import { OryDefaultComponents } from "../components" import { - OryCard, + OryClientConfiguration, OryFlowComponents, OryProvider, - OryClientConfiguration, + OryTwoStepCard, } from "@ory/elements-react" +import { PropsWithChildren } from "react" +import { OryDefaultComponents } from "../components" export type RecoveryFlowContextProps = { flow: RecoveryFlow @@ -32,7 +32,7 @@ export function Recovery({ flowType={FlowType.Recovery} components={components} > - {children ?? } + {children ?? } ) } diff --git a/packages/elements-react/src/theme/default/flows/registration.tsx b/packages/elements-react/src/theme/default/flows/registration.tsx index 39842ffc0..8815b80e5 100644 --- a/packages/elements-react/src/theme/default/flows/registration.tsx +++ b/packages/elements-react/src/theme/default/flows/registration.tsx @@ -1,13 +1,13 @@ "use client" import { FlowType, RegistrationFlow } from "@ory/client-fetch" -import { PropsWithChildren } from "react" -import { OryDefaultComponents } from "../components" import { OryClientConfiguration, OryFlowComponents, - OryCard, OryProvider, + OryTwoStepCard, } from "@ory/elements-react" +import { PropsWithChildren } from "react" +import { OryDefaultComponents } from "../components" type RegistrationFlowContextProps = { flow: RegistrationFlow @@ -32,7 +32,7 @@ export function Registration({ flowType={FlowType.Registration} components={components} > - {children ?? } + {children ?? } ) } diff --git a/packages/elements-react/src/theme/default/flows/settings.tsx b/packages/elements-react/src/theme/default/flows/settings.tsx index 095e6e46e..3583eb3c3 100644 --- a/packages/elements-react/src/theme/default/flows/settings.tsx +++ b/packages/elements-react/src/theme/default/flows/settings.tsx @@ -1,13 +1,13 @@ "use client" import { FlowType, SettingsFlow } from "@ory/client-fetch" -import { PropsWithChildren } from "react" -import { OryDefaultComponents } from "../components" import { - OryFlowComponents, OryClientConfiguration, + OryFlowComponents, OryProvider, - OryCard, + OryTwoStepCard, } from "@ory/elements-react" +import { PropsWithChildren } from "react" +import { OryDefaultComponents } from "../components" export type SettingsFlowContextProps = { flow: SettingsFlow @@ -32,7 +32,7 @@ export function Settings({ flowType={FlowType.Settings} components={components} > - {children ?? } + {children ?? } ) } diff --git a/packages/elements-react/src/theme/default/flows/verification.tsx b/packages/elements-react/src/theme/default/flows/verification.tsx index 70d58804e..b88ec6f4f 100644 --- a/packages/elements-react/src/theme/default/flows/verification.tsx +++ b/packages/elements-react/src/theme/default/flows/verification.tsx @@ -3,10 +3,10 @@ import { FlowType, VerificationFlow } from "@ory/client-fetch" import { PropsWithChildren } from "react" import { OryDefaultComponents } from "../components" import { - OryCard, - OryProvider, OryClientConfiguration, OryFlowComponents, + OryProvider, + OryTwoStepCard, } from "@ory/elements-react" export type VerificationFlowContextProps = { @@ -32,7 +32,7 @@ export function Verification({ flowType={FlowType.Verification} components={components} > - {children ?? } + {children ?? } ) } diff --git a/packages/elements-react/src/theme/default/provider-logos/apple.svg b/packages/elements-react/src/theme/default/provider-logos/apple.svg index 73db767fe..c85777c57 100644 --- a/packages/elements-react/src/theme/default/provider-logos/apple.svg +++ b/packages/elements-react/src/theme/default/provider-logos/apple.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/elements-react/src/theme/default/provider-logos/auth0.svg b/packages/elements-react/src/theme/default/provider-logos/auth0.svg index 0f88b421a..d6b8f9c5f 100644 --- a/packages/elements-react/src/theme/default/provider-logos/auth0.svg +++ b/packages/elements-react/src/theme/default/provider-logos/auth0.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/packages/elements-react/src/theme/default/provider-logos/discord.svg b/packages/elements-react/src/theme/default/provider-logos/discord.svg index 2c6b91316..e4ff75ce6 100644 --- a/packages/elements-react/src/theme/default/provider-logos/discord.svg +++ b/packages/elements-react/src/theme/default/provider-logos/discord.svg @@ -1,4 +1,4 @@ - - + + diff --git a/packages/elements-react/src/theme/default/provider-logos/facebook.svg b/packages/elements-react/src/theme/default/provider-logos/facebook.svg index 166b1848b..0a86dfecf 100644 --- a/packages/elements-react/src/theme/default/provider-logos/facebook.svg +++ b/packages/elements-react/src/theme/default/provider-logos/facebook.svg @@ -1,11 +1,11 @@ - + - + diff --git a/packages/elements-react/src/theme/default/provider-logos/generic.svg b/packages/elements-react/src/theme/default/provider-logos/generic.svg index 53f0b5125..a6dc383e0 100644 --- a/packages/elements-react/src/theme/default/provider-logos/generic.svg +++ b/packages/elements-react/src/theme/default/provider-logos/generic.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/elements-react/src/theme/default/provider-logos/github.svg b/packages/elements-react/src/theme/default/provider-logos/github.svg index 9bb4a7b46..ae7d0b2d5 100644 --- a/packages/elements-react/src/theme/default/provider-logos/github.svg +++ b/packages/elements-react/src/theme/default/provider-logos/github.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/packages/elements-react/src/theme/default/provider-logos/gitlab.svg b/packages/elements-react/src/theme/default/provider-logos/gitlab.svg index cb99d3916..b8dba799a 100644 --- a/packages/elements-react/src/theme/default/provider-logos/gitlab.svg +++ b/packages/elements-react/src/theme/default/provider-logos/gitlab.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/elements-react/src/theme/default/provider-logos/google.svg b/packages/elements-react/src/theme/default/provider-logos/google.svg index 78863c677..b8cf5b26b 100644 --- a/packages/elements-react/src/theme/default/provider-logos/google.svg +++ b/packages/elements-react/src/theme/default/provider-logos/google.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/packages/elements-react/src/theme/default/provider-logos/index.ts b/packages/elements-react/src/theme/default/provider-logos/index.ts index 0f44aa327..8d3969b74 100644 --- a/packages/elements-react/src/theme/default/provider-logos/index.ts +++ b/packages/elements-react/src/theme/default/provider-logos/index.ts @@ -1,7 +1,6 @@ // Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { FC, SVGProps } from "react" import apple from "./apple.svg" import auth0 from "./auth0.svg" import discord from "./discord.svg" @@ -16,7 +15,7 @@ import slack from "./slack.svg" import spotify from "./spotify.svg" import yandex from "./yandex.svg" -const logos: Record>> = { +const logos: Record = { apple, auth0, discord, diff --git a/packages/elements-react/src/theme/default/provider-logos/linkedin.svg b/packages/elements-react/src/theme/default/provider-logos/linkedin.svg index 6fa4897c2..28c24e28d 100644 --- a/packages/elements-react/src/theme/default/provider-logos/linkedin.svg +++ b/packages/elements-react/src/theme/default/provider-logos/linkedin.svg @@ -1,5 +1,5 @@ - - + + diff --git a/packages/elements-react/src/theme/default/provider-logos/microsoft.svg b/packages/elements-react/src/theme/default/provider-logos/microsoft.svg index 15d265d54..a0f13e239 100644 --- a/packages/elements-react/src/theme/default/provider-logos/microsoft.svg +++ b/packages/elements-react/src/theme/default/provider-logos/microsoft.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/packages/elements-react/src/theme/default/provider-logos/slack.svg b/packages/elements-react/src/theme/default/provider-logos/slack.svg index ceaf3ec6e..49ea22dcf 100644 --- a/packages/elements-react/src/theme/default/provider-logos/slack.svg +++ b/packages/elements-react/src/theme/default/provider-logos/slack.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/elements-react/src/theme/default/provider-logos/spotify.svg b/packages/elements-react/src/theme/default/provider-logos/spotify.svg index 98cc34b8c..7c5eb01d0 100644 --- a/packages/elements-react/src/theme/default/provider-logos/spotify.svg +++ b/packages/elements-react/src/theme/default/provider-logos/spotify.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/elements-react/src/theme/default/provider-logos/yandex.svg b/packages/elements-react/src/theme/default/provider-logos/yandex.svg index bef4a6cb4..32122cbf6 100644 --- a/packages/elements-react/src/theme/default/provider-logos/yandex.svg +++ b/packages/elements-react/src/theme/default/provider-logos/yandex.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/elements-react/src/types.ts b/packages/elements-react/src/types.ts index 8a4825fa5..f8d5c02d5 100644 --- a/packages/elements-react/src/types.ts +++ b/packages/elements-react/src/types.ts @@ -8,9 +8,8 @@ import { UiNodeInputAttributes, UiNodeTextAttributes, } from "@ory/client-fetch" -import React, { +import { ComponentPropsWithoutRef, - Dispatch, FormEventHandler, MouseEventHandler, } from "react" @@ -22,6 +21,13 @@ export type HeadlessButtonProps = { node: UiNode } & Omit, "children"> +export type HeadlessCurrentIdentifierProps = { + attributes: UiNodeInputAttributes + node: UiNode + onClick?: () => void + href?: string +} & Omit, "children" | "onClick"> + export type HeadlessLinkButtonProps = { attributes: UiNodeAnchorAttributes node: UiNode @@ -38,8 +44,7 @@ export type HeadlessTextProps = { } export type HeadlessAuthMethodListItemProps = { - setGroups: Dispatch> - setStep: Dispatch> + onClick: () => void group: string } diff --git a/packages/elements-react/src/util/ui/__test__/ui.spec.ts b/packages/elements-react/src/util/ui/__test__/ui.spec.ts new file mode 100644 index 000000000..3a81f5cc0 --- /dev/null +++ b/packages/elements-react/src/util/ui/__test__/ui.spec.ts @@ -0,0 +1,23 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import allMethodsInitialForm from "../../../../../elements-react-stories/src/elements-react/.stub-responses/login/1fa/all-methods/initial-form.json" + +import { renderHook } from "@tests/jest/test-utils" +import { useNodesGroups } from ".." +import { UiNode } from "@ory/client-fetch" + +describe("utils/ui", () => { + test("useNodesGroups", () => { + const { result } = renderHook(() => + useNodesGroups(allMethodsInitialForm.ui.nodes as UiNode[]), + ) + + expect(result.current.oidc).toHaveLength(2) + expect(result.current.default).toHaveLength(2) + expect(result.current.webauthn).toHaveLength(2) + expect(result.current.passkey).toHaveLength(3) + expect(result.current.password).toHaveLength(2) + expect(result.current.code).toHaveLength(1) + }) +}) diff --git a/packages/elements-react/src/util/ui/index.ts b/packages/elements-react/src/util/ui/index.ts index 5a8c20db2..682b3d654 100644 --- a/packages/elements-react/src/util/ui/index.ts +++ b/packages/elements-react/src/util/ui/index.ts @@ -9,6 +9,7 @@ import type { UiNodeInputAttributesOnloadTriggerEnum, UiNodeInputAttributesTypeEnum, } from "@ory/client-fetch" +import { useMemo } from "react" export function capitalize(s: string) { if (!s) { @@ -93,3 +94,18 @@ function triggerToFunction( } return triggerFn as () => void } + +export function useNodesGroups(nodes: UiNode[]) { + const groups = useMemo(() => { + const groups: Partial> = {} + + for (const node of nodes) { + const groupNodes = groups[node.group] ?? [] + groupNodes.push(node) + groups[node.group] = groupNodes + } + return groups + }, [nodes]) + + return groups +} diff --git a/packages/elements-react/tsconfig.json b/packages/elements-react/tsconfig.json index 549242d99..106512be5 100644 --- a/packages/elements-react/tsconfig.json +++ b/packages/elements-react/tsconfig.json @@ -29,6 +29,7 @@ "src/**/*.tsx", "src/global.d.ts", "src/tests/**/*.ts", - "src/tests/**/*.tsx" + "src/tests/**/*.tsx", + "tsup.config.ts" ] } diff --git a/packages/elements-react/tsup.config.ts b/packages/elements-react/tsup.config.ts index d3c246b09..fb2838620 100644 --- a/packages/elements-react/tsup.config.ts +++ b/packages/elements-react/tsup.config.ts @@ -40,8 +40,16 @@ export default defineConfig([ "react-intl", ], - /* @ts-ignore -- the types of the plugin are wrong? it still works.. */ - esbuildPlugins: [svgr()], + esbuildPlugins: [ + // @ts-expect-error - types seems to be wrong but it works + svgr({ + plugins: ["@svgr/plugin-svgo"], + svgProps: { + width: "{props?.width ? props.width : props?.size ?? 20}", + height: "{props?.height ? props.height : props?.size ?? 20}", + }, + }), + ], esbuildOptions(options) { options.banner = { js: '"use client"',