From 4254a53e5fc8d231023475b9472ab9eae71d40d9 Mon Sep 17 00:00:00 2001 From: Henning Perl Date: Wed, 10 Jan 2024 13:58:16 +0100 Subject: [PATCH] feat: passwordless strategy (#170) * feat: passwordless strategy * chore: revert formatting change * fix: spelling of lookupSecret -> lookup_secret * fix: show default nodes for webauthn * feat: add passkey auth story * feat: add passkey to user auth form --------- Co-authored-by: Jonas Hungershausen --- examples/nextjs-spa/src/pages/settings.tsx | 2 +- examples/preact-spa/src/settings.tsx | 2 +- examples/react-spa/src/Settings.tsx | 2 +- package-lock.json | 170 ++++++++++++++++++ package.json | 1 + src/locales/de.json | 2 + src/locales/en.json | 2 + src/locales/es.json | 2 + src/locales/fr.json | 2 + src/locales/nl.json | 2 + src/locales/pl.json | 2 + src/locales/pt.json | 2 + src/locales/se.json | 2 + src/markup-components/components.ts | 9 + src/react-components/ory/helpers/node.tsx | 20 ++- src/react-components/ory/helpers/utils.ts | 27 ++- src/react-components/ory/index.ts | 1 + .../ory/sections/passkey-settings-section.tsx | 32 ++++ .../ory/sections/passwordless-section.tsx | 55 +++++- src/react-components/ory/user-auth-card.tsx | 30 +++- .../ory/user-settings-card.tsx | 19 +- .../ory/user-settings-screen.tsx | 16 +- .../tests/translations.spec.ts | 47 ++--- src/stories/Ory/Auth.stories.tsx | 13 ++ src/stories/Ory/login-data.ts | 114 ++++++++++++ 25 files changed, 511 insertions(+), 65 deletions(-) create mode 100644 src/react-components/ory/sections/passkey-settings-section.tsx diff --git a/examples/nextjs-spa/src/pages/settings.tsx b/examples/nextjs-spa/src/pages/settings.tsx index c86f88350..6bf31ae03 100644 --- a/examples/nextjs-spa/src/pages/settings.tsx +++ b/examples/nextjs-spa/src/pages/settings.tsx @@ -108,7 +108,7 @@ const Settings: NextPageWithLayout = () => { "password", "totp", "webauthn", - "lookupSecret", + "lookup_secret", "oidc", ] as UserSettingsFlowType[] ).map((flowType: UserSettingsFlowType, index) => ( diff --git a/examples/preact-spa/src/settings.tsx b/examples/preact-spa/src/settings.tsx index 620c82a20..68a3674fe 100644 --- a/examples/preact-spa/src/settings.tsx +++ b/examples/preact-spa/src/settings.tsx @@ -76,7 +76,7 @@ export const Settings = () => { "password", "totp", "webauthn", - "lookupSecret", + "lookup_secret", "oidc", ] as UserSettingsFlowType[] ).map((flowType: UserSettingsFlowType, index) => ( diff --git a/examples/react-spa/src/Settings.tsx b/examples/react-spa/src/Settings.tsx index ad340efe4..788cc87fb 100644 --- a/examples/react-spa/src/Settings.tsx +++ b/examples/react-spa/src/Settings.tsx @@ -80,7 +80,7 @@ export const Settings = () => { "password", "totp", "webauthn", - "lookupSecret", + "lookup_secret", "oidc", ] as UserSettingsFlowType[] ).map((flowType: UserSettingsFlowType, index) => ( diff --git a/package-lock.json b/package-lock.json index a8f88924d..78d27f349 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ }, "devDependencies": { "@babel/core": "7.18.10", + "@formatjs/cli-lib": "6.3.3", "@ory/client": "1.2.10", "@ory/integrations": "1.1.5", "@playwright/experimental-ct-react": "1.38.0", @@ -3847,6 +3848,141 @@ "integrity": "sha512-ou3elfqG/hZsbmF4bxeJhPHIf3G2pm0ujc39hYEZrfVqt7Vk/Zji6CXc3W0pmYM8BW1g40U+akTl9DKZhFhInQ==", "dev": true }, + "node_modules/@formatjs/cli-lib": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@formatjs/cli-lib/-/cli-lib-6.3.3.tgz", + "integrity": "sha512-qQwrsghvp3Bg5rxP8xRNk2iloIvgClLhaBD30J4fxM6LucyGvYa5aTVNOy2lgqUKoGT51QjxFuzZxhx4YZdiqQ==", + "dev": true, + "dependencies": { + "@formatjs/icu-messageformat-parser": "2.7.3", + "@formatjs/ts-transformer": "3.13.9", + "@types/estree": "^1.0.0", + "@types/fs-extra": "^9.0.1", + "@types/json-stable-stringify": "^1.0.32", + "@types/node": "14 || 16 || 17", + "chalk": "^4.0.0", + "commander": "8", + "fast-glob": "^3.2.7", + "fs-extra": "10", + "json-stable-stringify": "^1.0.1", + "loud-rejection": "^2.2.0", + "tslib": "^2.4.0", + "typescript": "5" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "@vue/compiler-core": "^3.3.4", + "vue": "^3.3.4" + }, + "peerDependenciesMeta": { + "@vue/compiler-core": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@formatjs/cli-lib/node_modules/@formatjs/ecma402-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.0.tgz", + "integrity": "sha512-PEVLoa3zBevWSCZzPIM/lvPCi8P5l4G+NXQMc/CjEiaCWgyHieUoo0nM7Bs0n/NbuQ6JpXEolivQ9pKSBHaDlA==", + "dev": true, + "dependencies": { + "@formatjs/intl-localematcher": "0.5.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/cli-lib/node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.3.tgz", + "integrity": "sha512-X/jy10V9S/vW+qlplqhMUxR8wErQ0mmIYSq4mrjpjDl9mbuGcCILcI1SUYkL5nlM4PJqpc0KOS0bFkkJNPxYRw==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.18.0", + "@formatjs/icu-skeleton-parser": "1.7.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/cli-lib/node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.7.0.tgz", + "integrity": "sha512-Cfdo/fgbZzpN/jlN/ptQVe0lRHora+8ezrEeg2RfrNjyp+YStwBy7cqDY8k5/z2LzXg6O0AdzAV91XS0zIWv+A==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.18.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/cli-lib/node_modules/@formatjs/intl-localematcher": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.2.tgz", + "integrity": "sha512-txaaE2fiBMagLrR4jYhxzFO6wEdEG4TPMqrzBAcbr4HFUYzH/YC+lg6OIzKCHm8WgDdyQevxbAAV1OgcXctuGw==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/cli-lib/node_modules/@formatjs/ts-transformer": { + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.13.9.tgz", + "integrity": "sha512-J3kmCHOwkc0Tru0ZnBHPVDIwHCcaNh/zB8ZU4VQFBH2jhaOku0drym/hjz+f9/PCKLutd3Q7alUi2+Z2VpBIng==", + "dev": true, + "dependencies": { + "@formatjs/icu-messageformat-parser": "2.7.3", + "@types/json-stable-stringify": "^1.0.32", + "@types/node": "14 || 16 || 17", + "chalk": "^4.0.0", + "json-stable-stringify": "^1.0.1", + "tslib": "^2.4.0", + "typescript": "5" + }, + "peerDependencies": { + "ts-jest": ">=27" + }, + "peerDependenciesMeta": { + "ts-jest": { + "optional": true + } + } + }, + "node_modules/@formatjs/cli-lib/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 + }, + "node_modules/@formatjs/cli-lib/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "dev": true + }, + "node_modules/@formatjs/cli-lib/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@formatjs/cli-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@formatjs/ecma402-abstract": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz", @@ -11309,6 +11445,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/glob": { "version": "7.2.0", "dev": true, @@ -14434,6 +14579,18 @@ "version": "3.1.1", "license": "MIT" }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "license": "BSD-2-Clause" @@ -20019,6 +20176,19 @@ "loose-envify": "cli.js" } }, + "node_modules/loud-rejection": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-2.2.0.tgz", + "integrity": "sha512-S0FayMXku80toa5sZ6Ro4C+s+EtFDCsyJNG/AzFMfX3AxD5Si4dZsgzm/kKnbOxHl5Cv8jBlno8+3XYIh2pNjQ==", + "dev": true, + "dependencies": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "dev": true, diff --git a/package.json b/package.json index 5687fd21f..58d9aeb33 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "homepage": "https://github.com/ory/elements#readme", "devDependencies": { "@babel/core": "7.18.10", + "@formatjs/cli-lib": "6.3.3", "@ory/client": "1.2.10", "@ory/integrations": "1.1.5", "@playwright/experimental-ct-react": "1.38.0", diff --git a/src/locales/de.json b/src/locales/de.json index 25d7812e5..b02489475 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Profil", "settings.navigation-totp": "Zwei-Faktor App", "settings.navigation-webauthn": "Sicherheitsschlüssel", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Hier können Sie Einstellungen zu Ihrem Konto vornehmen. Für manche Einstellungen müssen Sie Ihre Identität erneut bestätigen.", "settings.title": "Kontoeinstellungen", "settings.title-lookup-secret": "Manage 2FA Backup Recovery Codes", @@ -167,6 +168,7 @@ "settings.title-profile": "Profil Einstellungen", "settings.title-totp": "Zwei-Faktor TOTP App", "settings.title-webauthn": "Sicherheitsschlüssel verwalten", + "settings.title-passkey": "Passkeys verwalten", "verification.registration-button": "Registrieren", "verification.registration-label": "Sie haben noch kein Konto?", "verification.title": "Verifizieren Sie ihr Konto" diff --git a/src/locales/en.json b/src/locales/en.json index 06c919ee2..bd995ecb9 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Profile", "settings.navigation-totp": "Authenticator App", "settings.navigation-webauthn": "Hardware Tokens", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Here you can manage settings related to your account. Keep in mind that certain actions require you to re-authenticate.", "settings.title": "Account Settings", "settings.title-lookup-secret": "Manage 2FA Backup Recovery Codes", @@ -167,6 +168,7 @@ "settings.title-profile": "Profile Settings", "settings.title-totp": "Manage 2FA TOTP Authenticator App", "settings.title-webauthn": "Manage Hardware Tokens", + "settings.title-passkey": "Manage Passkeys", "verification.registration-button": "Sign up", "verification.registration-label": "Don't have an account?", "verification.title": "Verify your account" diff --git a/src/locales/es.json b/src/locales/es.json index 913dc42c1..5737b6852 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Perfil", "settings.navigation-totp": "Aplicación Autenticadora", "settings.navigation-webauthn": "Tokens de Hardware", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Aquí puede gestionar las configuraciones relacionadas con su cuenta. Tenga en cuenta que ciertas acciones requieren que vuelva a autenticarse.", "settings.title": "Configuraciones de la Cuenta", "settings.title-lookup-secret": "Gestionar Códigos de Recuperación de Respaldo de 2FA", @@ -167,6 +168,7 @@ "settings.title-profile": "Configuraciones del Perfil", "settings.title-totp": "Gestionar Aplicación Autenticadora de 2FA", "settings.title-webauthn": "Gestionar Tokens de Hardware", + "settings.title-passkey": "Gestionar Passkeys", "verification.registration-button": "Registrarse", "verification.registration-label": "¿No tiene una cuenta?", "verification.title": "Verificar su cuenta" diff --git a/src/locales/fr.json b/src/locales/fr.json index f68c60dd8..d2dc1efab 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Profil", "settings.navigation-totp": "Application d'authentification TOTP", "settings.navigation-webauthn": "Tokens matériels", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Ici, vous pouvez gérer les paramètres liés à votre compte. Gardez à l'esprit que certaines actions nécessitent une nouvelle authentification.", "settings.title": "Paramètres du compte", "settings.title-lookup-secret": "Gérer les codes de récupération 2FA", @@ -167,6 +168,7 @@ "settings.title-profile": "Paramètres de profil", "settings.title-totp": "Gérer l'application d'authentification TOTP 2FA", "settings.title-webauthn": "Gérer les tokens matériels", + "settings.title-passkey": "Gérer les Passkeys", "verification.registration-button": "S'inscrire", "verification.registration-label": "Vous n'avez pas de compte ?", "verification.title": "Vérifiez votre compte" diff --git a/src/locales/nl.json b/src/locales/nl.json index a99a51523..f23eb29b2 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Profiel", "settings.navigation-totp": "Authenticator App", "settings.navigation-webauthn": "Hardware Tokens", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Hier kun je instellingen beheren die verband houden met je account. Houd er rekening mee dat bepaalde acties vereisen dat je opnieuw wordt geauthenticeerd.", "settings.title": "Accountinstellingen", "settings.title-lookup-secret": "Beheer 2FA Backup Herstelcodes", @@ -167,6 +168,7 @@ "settings.title-profile": "Profielinstellingen", "settings.title-totp": "Beheer 2FA TOTP Authenticator App", "settings.title-webauthn": "Beheer Hardware Tokens", + "settings.title-passkey": "Beheer Passkeys", "verification.registration-button": "Registreren", "verification.registration-label": "Heb je nog geen account?", "verification.title": "Verifieer je account" diff --git a/src/locales/pl.json b/src/locales/pl.json index c39a2721e..3cdaa37ad 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Profil", "settings.navigation-totp": "Aplikacja Autentykator", "settings.navigation-webauthn": "Tokeny Sprzętowe", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Tutaj możesz zarządzać ustawieniami związanymi z Twoim kontem. Miej na uwadze że niektóre akcje mogą wymagać ponownej uwierzytelnienia.", "settings.title": "Ustawienia Konta", "settings.title-lookup-secret": "Zarządzaj kodami odzyskiwania 2FA", @@ -167,6 +168,7 @@ "settings.title-profile": "Ustawienia Profilu", "settings.title-totp": "Zarządzaj aplikacją autentykator 2FA TOTP", "settings.title-webauthn": "Zarządzaj tokenami sprzętowymi", + "settings.title-passkey": "Zarządzaj Passkeys", "verification.registration-button": "Zarejestruj się", "verification.registration-label": "Nie posiadasz konta?", "verification.title": "Zweryfikuj konto" diff --git a/src/locales/pt.json b/src/locales/pt.json index 9d6b7b288..ebcf7e88a 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Perfil", "settings.navigation-totp": "Aplicação Autenticador 2FA", "settings.navigation-webauthn": "Tokens de Hardware", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Aqui pode gerar configurações relacionadas com a sua conta. Lembre-se de que certas ações exigem que efetue novamente login.", "settings.title": "Configurações da Conta", "settings.title-lookup-secret": "Gerar Códigos de Recuperação de Backup de 2FA", @@ -167,6 +168,7 @@ "settings.title-profile": "Configurações de Perfil", "settings.title-totp": "Gerar Aplicação Autenticador 2FA", "settings.title-webauthn": "Gerar Tokens de Hardware", + "settings.title-passkey": "Gerar Passkeys", "verification.registration-button": "Registar", "verification.registration-label": "Não tem uma conta?", "verification.title": "Verifique a sua conta" diff --git a/src/locales/se.json b/src/locales/se.json index 447c54b36..34f17ffc2 100644 --- a/src/locales/se.json +++ b/src/locales/se.json @@ -158,6 +158,7 @@ "settings.navigation-profile": "Profil", "settings.navigation-totp": "Autentiserings App", "settings.navigation-webauthn": "Hårdvaru Tokens", + "settings.navigation-passkey": "Passkeys", "settings.subtitle-instructions": "Här kan du hantera inställningar relaterade till ditt konto. Tänk på att vissa åtgärder kräver att du autentiseras på nytt.", "settings.title": "Kontoinställningar", "settings.title-lookup-secret": "Hantera 2FA backup-återställningskoder", @@ -167,6 +168,7 @@ "settings.title-profile": "Profilinställningar", "settings.title-totp": "Hantera 2FA TOTP Autentiserings App", "settings.title-webauthn": "Hantera Hårdvaru Tokens", + "settings.title-passkey": "Hantera Passkeys", "verification.registration-button": "Skapa konto", "verification.registration-label": "Har du inget konto?", "verification.title": "Verifiera ditt konto" diff --git a/src/markup-components/components.ts b/src/markup-components/components.ts index c5a1fdba3..de0010ee7 100644 --- a/src/markup-components/components.ts +++ b/src/markup-components/components.ts @@ -59,6 +59,8 @@ import { UserSettingsScreenProps, WebAuthnSettingsProps, WebAuthnSettingsSection as webAuthnSettingsSection, + PasskeySettingsSection as passkeySettingsSection, + PasskeySettingsProps, } from "../react-components" import { ComponentWrapper, Context } from "./component-wrapper" @@ -197,6 +199,13 @@ export const WebAuthnSettingsSection = ( return ComponentWrapper(webAuthnSettingsSection, props, context) } +export const PasskeySettingsSection = ( + props: PasskeySettingsProps, + context: Context = {}, +) => { + return ComponentWrapper(passkeySettingsSection, props, context) +} + export const OIDCSettingsSection = ( props: OIDCSettingsProps, context: Context = {}, diff --git a/src/react-components/ory/helpers/node.tsx b/src/react-components/ory/helpers/node.tsx index 53ade5a7d..c46d2db1d 100644 --- a/src/react-components/ory/helpers/node.tsx +++ b/src/react-components/ory/helpers/node.tsx @@ -1,4 +1,4 @@ -import { UiNode, UiText } from "@ory/client" +import { UiNode, UiNodeAttributes, UiText } from "@ory/client" import { isUiNodeAnchorAttributes, isUiNodeImageAttributes, @@ -182,6 +182,18 @@ export const uiTextToFormattedMessage = ( ) } +function dataAttributes(attrs: UiNodeAttributes): Record { + return Object.entries(attrs).reduce>( + (accumulator, [key, value]) => { + if (key.startsWith("data-")) { + accumulator[key] = value as string + } + return accumulator + }, + {}, + ) +} + export const Node = ({ node, className, @@ -205,6 +217,7 @@ export const Node = ({ header={formatMessage(node.meta.label)} width={node.attributes.width} height={node.attributes.height} + {...dataAttributes(node.attributes)} /> ) } else if (isUiNodeTextAttributes(node.attributes)) { @@ -307,6 +320,7 @@ export const Node = ({ disabled={attrs.disabled} {...(buttonSocialOverrideProps && buttonSocialOverrideProps)} {...submit} + {...dataAttributes(attrs)} /> ) : (