From 389852248fb78afb2abcceca20776eb76bbd9cd9 Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 7 Mar 2026 00:16:54 +0530 Subject: [PATCH 1/8] Enhance BaseLanguageSwitcher: add logic to handle single language scenarios and improve accessibility --- .../LanguageSwitcher/BaseLanguageSwitcher.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx b/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx index 7c0da8f7..22a4f53e 100644 --- a/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx +++ b/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx @@ -30,7 +30,7 @@ import { useInteractions, useRole, } from '@floating-ui/react'; -import {FC, ReactElement, ReactNode, useState} from 'react'; +import {FC, ReactElement, ReactNode, useEffect, useState} from 'react'; import useStyles from './BaseLanguageSwitcher.styles'; import useTheme from '../../../contexts/Theme/useTheme'; import Check from '../../primitives/Icons/Check'; @@ -109,6 +109,13 @@ const BaseLanguageSwitcher: FC = ({ const {theme, colorScheme} = useTheme(); const styles: Record = useStyles(theme, colorScheme); const [isOpen, setIsOpen] = useState(false); + const hasMultipleLanguages = languages.length > 1; + + useEffect(() => { + if (!hasMultipleLanguages && isOpen) { + setIsOpen(false); + } + }, [hasMultipleLanguages, isOpen]); const {refs, floatingStyles, context} = useFloating({ middleware: [offset(4), flip(), shift()], @@ -117,9 +124,9 @@ const BaseLanguageSwitcher: FC = ({ whileElementsMounted: autoUpdate, }); - const click: ReturnType = useClick(context); - const dismiss: ReturnType = useDismiss(context); - const role: ReturnType = useRole(context, {role: 'listbox'}); + const click: ReturnType = useClick(context, {enabled: hasMultipleLanguages}); + const dismiss: ReturnType = useDismiss(context, {enabled: hasMultipleLanguages}); + const role: ReturnType = useRole(context, {enabled: hasMultipleLanguages, role: 'listbox'}); const {getReferenceProps, getFloatingProps} = useInteractions([click, dismiss, role]); const currentOption: LanguageOption | undefined = languages.find((l: LanguageOption) => l.code === currentLanguage); @@ -149,10 +156,10 @@ const BaseLanguageSwitcher: FC = ({ > {currentOption && {currentOption.emoji}} {currentOption?.displayName ?? currentLanguage} - + {hasMultipleLanguages && } - {isOpen && ( + {isOpen && hasMultipleLanguages && (
Date: Sat, 7 Mar 2026 00:23:11 +0530 Subject: [PATCH 2/8] Refactor LanguageSwitcher: improve language resolution logic to ensure current language is always included --- .../LanguageSwitcher/LanguageSwitcher.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx b/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx index 512c4a09..f9856845 100644 --- a/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx +++ b/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx @@ -85,15 +85,21 @@ const LanguageSwitcher: FC = ({children, className}: Lang const {currentLanguage} = useTranslation(); const availableLanguageCodes: string[] = meta?.i18n?.languages ?? []; + const effectiveLanguageCodes: string[] = useMemo(() => { + const fallbackCodes: string[] = availableLanguageCodes.length > 0 ? availableLanguageCodes : [currentLanguage]; + + // Ensure the current language is always resolvable for display label and emoji. + return Array.from(new Set([currentLanguage, ...fallbackCodes])); + }, [availableLanguageCodes, currentLanguage]); const languages: LanguageOption[] = useMemo( () => - availableLanguageCodes.map((code: string) => ({ + effectiveLanguageCodes.map((code: string) => ({ code, - displayName: resolveLocaleDisplayName(code, currentLanguage), + displayName: resolveLocaleDisplayName(code, currentLanguage) || code, emoji: resolveLocaleEmoji(code), })), - [availableLanguageCodes, currentLanguage], + [effectiveLanguageCodes, currentLanguage], ); const handleLanguageChange = (language: string): void => { From 553058e5a44183db62f378a1f8e2fadd97f9f071 Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 7 Mar 2026 00:25:27 +0530 Subject: [PATCH 3/8] Refactor LanguageSwitcher: stabilize display names across UI language switches by resolving labels in their own locale --- .../presentation/LanguageSwitcher/LanguageSwitcher.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx b/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx index f9856845..399f407f 100644 --- a/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx +++ b/packages/react/src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx @@ -96,10 +96,11 @@ const LanguageSwitcher: FC = ({children, className}: Lang () => effectiveLanguageCodes.map((code: string) => ({ code, - displayName: resolveLocaleDisplayName(code, currentLanguage) || code, + // Resolve each label in its own locale so option names stay stable across UI language switches. + displayName: resolveLocaleDisplayName(code, code) || code, emoji: resolveLocaleEmoji(code), })), - [effectiveLanguageCodes, currentLanguage], + [effectiveLanguageCodes], ); const handleLanguageChange = (language: string): void => { From 7199414ed8669c3ee06ef104314b2a4fcfa3dc6a Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 7 Mar 2026 02:22:41 +0530 Subject: [PATCH 4/8] Refactor EmbeddedFlowActionVariant: replace 'SOCIAL' with 'OUTLINED' for clarity; update SubmitButton and AuthOptionFactory to support new variant; add ArrowRightLeft icon component and register it in flowIconRegistry --- .../src/models/v2/embedded-flow-v2.ts | 4 +- .../src/components/adapters/SubmitButton.tsx | 1 + .../presentation/auth/AuthOptionFactory.tsx | 8 ++- .../primitives/Icons/ArrowRightLeft.tsx | 52 +++++++++++++++++++ .../primitives/Icons/flowIconRegistry.tsx | 2 + 5 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 packages/react/src/components/primitives/Icons/ArrowRightLeft.tsx diff --git a/packages/javascript/src/models/v2/embedded-flow-v2.ts b/packages/javascript/src/models/v2/embedded-flow-v2.ts index 1f3d7068..cba08565 100644 --- a/packages/javascript/src/models/v2/embedded-flow-v2.ts +++ b/packages/javascript/src/models/v2/embedded-flow-v2.ts @@ -102,8 +102,8 @@ export enum EmbeddedFlowActionVariant { /** Secondary action button with moderate visual emphasis */ Secondary = 'SECONDARY', - /** Social media action button (e.g., Google, Facebook) */ - Social = 'SOCIAL', + /** Outlined action button for secondary emphasis */ + Outlined = 'OUTLINED', /** Success action button for positive confirmations */ Success = 'SUCCESS', diff --git a/packages/react/src/components/adapters/SubmitButton.tsx b/packages/react/src/components/adapters/SubmitButton.tsx index 16a7a345..9b7cf606 100644 --- a/packages/react/src/components/adapters/SubmitButton.tsx +++ b/packages/react/src/components/adapters/SubmitButton.tsx @@ -47,6 +47,7 @@ const ButtonComponent: FC = ({ case 'TEXT': return {color: 'primary' as const, variant: 'text' as const}; case 'SOCIAL': + case 'OUTLINED': return {color: 'primary' as const, variant: 'outline' as const}; default: return {color: 'primary' as const, variant: 'solid' as const}; diff --git a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx index d3f47d09..9687201f 100644 --- a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx +++ b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx @@ -143,6 +143,7 @@ const createAuthComponentFromFlow = ( options: { buttonClassName?: string; inputClassName?: string; + inStack?: boolean; key?: string | number; /** Flow metadata for resolving {{meta(...)}} expressions at render time */ meta?: FlowMetadataResponse | null; @@ -355,6 +356,8 @@ const createAuthComponentFromFlow = ( } case EmbeddedFlowComponentType.Image: { + const explicitHeight: string = resolve(component.height?.toString()); + const explicitWidth: string = resolve(component.width?.toString()); return ( = ({color = 'currentColor', size = 24}: ArrowRightLeftProps) => ( + + + + + + +); + +ArrowRightLeft.displayName = 'ArrowRightLeft'; + +export default ArrowRightLeft; diff --git a/packages/react/src/components/primitives/Icons/flowIconRegistry.tsx b/packages/react/src/components/primitives/Icons/flowIconRegistry.tsx index 9dd72eee..8d85dfd0 100644 --- a/packages/react/src/components/primitives/Icons/flowIconRegistry.tsx +++ b/packages/react/src/components/primitives/Icons/flowIconRegistry.tsx @@ -18,6 +18,7 @@ import {FC} from 'react'; import ArrowLeftRight from './ArrowLeftRight'; +import ArrowRightLeft from './ArrowRightLeft'; export interface FlowIconProps { color?: string; @@ -30,6 +31,7 @@ export interface FlowIconProps { */ const flowIconRegistry: Record> = { ArrowLeftRight, + ArrowRightLeft, }; export default flowIconRegistry; From 3707df804ffae199a3dc44f279e8a5527e604aa4 Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 7 Mar 2026 02:24:39 +0530 Subject: [PATCH 5/8] =?UTF-8?q?Add=20changeset=20=F0=9F=A6=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/metal-lemons-pick.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/metal-lemons-pick.md diff --git a/.changeset/metal-lemons-pick.md b/.changeset/metal-lemons-pick.md new file mode 100644 index 00000000..c715d1b3 --- /dev/null +++ b/.changeset/metal-lemons-pick.md @@ -0,0 +1,6 @@ +--- +'@asgardeo/javascript': patch +'@asgardeo/react': patch +--- + +Improve `` & other components From 02455738b50d10cef7d7a4ecee6f7efa449c2505 Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 7 Mar 2026 02:30:51 +0530 Subject: [PATCH 6/8] Refactor matchesSocialProvider: enhance button text matching logic for social providers to improve detection accuracy --- .../components/presentation/auth/AuthOptionFactory.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx index 9687201f..803ab1d1 100644 --- a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx +++ b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx @@ -110,14 +110,14 @@ const matchesSocialProvider = ( buttonText: string, provider: string, authType: AuthType, - componentVariant?: string, ): boolean => { const providerId: any = `${provider}_auth`; const providerMatches: any = actionId === providerId || eventType === providerId; - // For social variant, also check button text for provider name - if (componentVariant?.toUpperCase() === EmbeddedFlowActionVariant.Social) { - return buttonText.toLowerCase().includes(provider); + // Social buttons usually have "Sign in with X" or "Continue with X" text, + // so also check button text for the provider name to increase chances of correct detection (especially for signup flows where action IDs are less standardized) + if (buttonText.toLowerCase().includes(provider)) { + return true; } // For signup, also check button text From 3539f0f303bb9b1c678ebd9faf9cd2185f8cca38 Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 7 Mar 2026 02:45:44 +0530 Subject: [PATCH 7/8] Fix lint issues --- packages/javascript/src/models/v2/embedded-flow-v2.ts | 6 +++--- .../presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx | 2 +- .../src/components/presentation/auth/AuthOptionFactory.tsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/javascript/src/models/v2/embedded-flow-v2.ts b/packages/javascript/src/models/v2/embedded-flow-v2.ts index cba08565..dca4b72c 100644 --- a/packages/javascript/src/models/v2/embedded-flow-v2.ts +++ b/packages/javascript/src/models/v2/embedded-flow-v2.ts @@ -96,15 +96,15 @@ export enum EmbeddedFlowActionVariant { /** Link-styled action button */ Link = 'LINK', + /** Outlined action button for secondary emphasis */ + Outlined = 'OUTLINED', + /** Primary action button with highest visual emphasis */ Primary = 'PRIMARY', /** Secondary action button with moderate visual emphasis */ Secondary = 'SECONDARY', - /** Outlined action button for secondary emphasis */ - Outlined = 'OUTLINED', - /** Success action button for positive confirmations */ Success = 'SUCCESS', diff --git a/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx b/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx index 22a4f53e..a38f1966 100644 --- a/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx +++ b/packages/react/src/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.tsx @@ -109,7 +109,7 @@ const BaseLanguageSwitcher: FC = ({ const {theme, colorScheme} = useTheme(); const styles: Record = useStyles(theme, colorScheme); const [isOpen, setIsOpen] = useState(false); - const hasMultipleLanguages = languages.length > 1; + const hasMultipleLanguages: boolean = languages.length > 1; useEffect(() => { if (!hasMultipleLanguages && isOpen) { diff --git a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx index 803ab1d1..ee35222d 100644 --- a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx +++ b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx @@ -22,7 +22,6 @@ import { EmbeddedFlowComponentV2 as EmbeddedFlowComponent, EmbeddedFlowComponentTypeV2 as EmbeddedFlowComponentType, EmbeddedFlowTextVariantV2 as EmbeddedFlowTextVariant, - EmbeddedFlowActionVariantV2 as EmbeddedFlowActionVariant, EmbeddedFlowEventTypeV2 as EmbeddedFlowEventType, createPackageComponentLogger, resolveVars, @@ -110,6 +109,7 @@ const matchesSocialProvider = ( buttonText: string, provider: string, authType: AuthType, + _componentVariant?: string, ): boolean => { const providerId: any = `${provider}_auth`; const providerMatches: any = actionId === providerId || eventType === providerId; @@ -142,8 +142,8 @@ const createAuthComponentFromFlow = ( authType: AuthType, options: { buttonClassName?: string; - inputClassName?: string; inStack?: boolean; + inputClassName?: string; key?: string | number; /** Flow metadata for resolving {{meta(...)}} expressions at render time */ meta?: FlowMetadataResponse | null; From c2fb7189d37f3484c50e936962910f08fed199e8 Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 7 Mar 2026 19:16:31 +0530 Subject: [PATCH 8/8] Fix lint issues --- .../react/src/components/presentation/auth/AuthOptionFactory.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx index ee35222d..a1c711f2 100644 --- a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx +++ b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx @@ -109,6 +109,7 @@ const matchesSocialProvider = ( buttonText: string, provider: string, authType: AuthType, + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ _componentVariant?: string, ): boolean => { const providerId: any = `${provider}_auth`;