From 96d5194a694e13216d545b7e9772d9e31f1c3dcd Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Thu, 9 Apr 2026 00:36:13 +0530 Subject: [PATCH 1/2] Add flow native render support for invite flows --- packages/i18n/src/models/i18n.ts | 2 + packages/i18n/src/translations/en-US.ts | 2 + packages/i18n/src/translations/fr-FR.ts | 2 + packages/i18n/src/translations/hi-IN.ts | 2 + packages/i18n/src/translations/ja-JP.ts | 2 + packages/i18n/src/translations/pt-BR.ts | 2 + packages/i18n/src/translations/pt-PT.ts | 2 + packages/i18n/src/translations/si-LK.ts | 2 + packages/i18n/src/translations/ta-IN.ts | 2 + packages/i18n/src/translations/te-IN.ts | 2 + .../src/models/v2/embedded-flow-v2.ts | 9 + .../auth/AcceptInvite/v2/BaseAcceptInvite.tsx | 53 +----- .../presentation/auth/AuthOptionFactory.tsx | 9 + .../auth/InviteUser/v2/BaseInviteUser.tsx | 165 +----------------- .../auth/InviteUser/v2/InviteUser.tsx | 7 - .../CopyableText/CopyableText.styles.ts | 64 +++++++ .../primitives/CopyableText/CopyableText.tsx | 83 +++++++++ .../primitives/CopyableText/index.ts | 20 +++ 18 files changed, 212 insertions(+), 218 deletions(-) create mode 100644 packages/react/src/components/primitives/CopyableText/CopyableText.styles.ts create mode 100644 packages/react/src/components/primitives/CopyableText/CopyableText.tsx create mode 100644 packages/react/src/components/primitives/CopyableText/index.ts diff --git a/packages/i18n/src/models/i18n.ts b/packages/i18n/src/models/i18n.ts index 667847e9..a3f8340a 100644 --- a/packages/i18n/src/models/i18n.ts +++ b/packages/i18n/src/models/i18n.ts @@ -40,6 +40,8 @@ export interface I18nTranslations { /* Display */ 'elements.display.divider.or_separator': string; + 'elements.display.copyable_text.copy': string; + 'elements.display.copyable_text.copied': string; /* Fields */ 'elements.fields.generic.placeholder': string; diff --git a/packages/i18n/src/translations/en-US.ts b/packages/i18n/src/translations/en-US.ts index 679fe736..dd12f1a1 100644 --- a/packages/i18n/src/translations/en-US.ts +++ b/packages/i18n/src/translations/en-US.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'OR', + 'elements.display.copyable_text.copy': 'Copy', + 'elements.display.copyable_text.copied': 'Copied!', /* Fields */ 'elements.fields.generic.placeholder': 'Enter your {field}', diff --git a/packages/i18n/src/translations/fr-FR.ts b/packages/i18n/src/translations/fr-FR.ts index 77280bd3..0a1b190c 100644 --- a/packages/i18n/src/translations/fr-FR.ts +++ b/packages/i18n/src/translations/fr-FR.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'OU', + 'elements.display.copyable_text.copy': 'Copie', + 'elements.display.copyable_text.copied': 'Copié!', /* Fields */ 'elements.fields.generic.placeholder': 'Entrez votre {field}', diff --git a/packages/i18n/src/translations/hi-IN.ts b/packages/i18n/src/translations/hi-IN.ts index 334ba8cc..0a46a1d2 100644 --- a/packages/i18n/src/translations/hi-IN.ts +++ b/packages/i18n/src/translations/hi-IN.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'या', + 'elements.display.copyable_text.copy': 'प्रतिलिपि', + 'elements.display.copyable_text.copied': 'नकल की गई!', /* Fields */ 'elements.fields.generic.placeholder': '{field} दर्ज करें', diff --git a/packages/i18n/src/translations/ja-JP.ts b/packages/i18n/src/translations/ja-JP.ts index 9d9ad5f1..511b2abc 100644 --- a/packages/i18n/src/translations/ja-JP.ts +++ b/packages/i18n/src/translations/ja-JP.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'または', + 'elements.display.copyable_text.copy': 'コピー', + 'elements.display.copyable_text.copied': 'コピーしました!', /* Fields */ 'elements.fields.generic.placeholder': '{field}を入力してください', diff --git a/packages/i18n/src/translations/pt-BR.ts b/packages/i18n/src/translations/pt-BR.ts index 74f71483..3a233115 100644 --- a/packages/i18n/src/translations/pt-BR.ts +++ b/packages/i18n/src/translations/pt-BR.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'OU', + 'elements.display.copyable_text.copy': 'Cópia', + 'elements.display.copyable_text.copied': 'Copiado!', /* Fields */ 'elements.fields.generic.placeholder': 'Digite seu {field}', diff --git a/packages/i18n/src/translations/pt-PT.ts b/packages/i18n/src/translations/pt-PT.ts index 5eb98a34..da86b174 100644 --- a/packages/i18n/src/translations/pt-PT.ts +++ b/packages/i18n/src/translations/pt-PT.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'OU', + 'elements.display.copyable_text.copy': 'Cópia', + 'elements.display.copyable_text.copied': 'Copiado!', /* Fields */ 'elements.fields.generic.placeholder': 'Introduza o seu {field}', diff --git a/packages/i18n/src/translations/si-LK.ts b/packages/i18n/src/translations/si-LK.ts index faf1cffc..0b1b4103 100644 --- a/packages/i18n/src/translations/si-LK.ts +++ b/packages/i18n/src/translations/si-LK.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'හෝ', + 'elements.display.copyable_text.copy': 'පිටපත් කරන්න', + 'elements.display.copyable_text.copied': 'පිටපත් කළා!', /* Fields */ 'elements.fields.generic.placeholder': 'ඔබේ {field} ඇතුලත් කරන්න', diff --git a/packages/i18n/src/translations/ta-IN.ts b/packages/i18n/src/translations/ta-IN.ts index 6683ff35..f9a2d635 100644 --- a/packages/i18n/src/translations/ta-IN.ts +++ b/packages/i18n/src/translations/ta-IN.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'அல்லது', + 'elements.display.copyable_text.copy': 'நகலெடுக்கவும்', + 'elements.display.copyable_text.copied': 'நகலெடுக்கப்பட்டது!', /* Fields */ 'elements.fields.generic.placeholder': '{field} உள்ளிடவும்', diff --git a/packages/i18n/src/translations/te-IN.ts b/packages/i18n/src/translations/te-IN.ts index d626bcb5..509cbf2e 100644 --- a/packages/i18n/src/translations/te-IN.ts +++ b/packages/i18n/src/translations/te-IN.ts @@ -43,6 +43,8 @@ const translations: I18nTranslations = { /* Display */ 'elements.display.divider.or_separator': 'లేదా', + 'elements.display.copyable_text.copy': 'కాపీ చేయండి', + 'elements.display.copyable_text.copied': 'కాపీ చేయబడింది!', /* Fields */ 'elements.fields.generic.placeholder': 'మీ {field} ను నమోదు చేయండి', diff --git a/packages/javascript/src/models/v2/embedded-flow-v2.ts b/packages/javascript/src/models/v2/embedded-flow-v2.ts index 8092fd28..a479ae36 100644 --- a/packages/javascript/src/models/v2/embedded-flow-v2.ts +++ b/packages/javascript/src/models/v2/embedded-flow-v2.ts @@ -47,6 +47,9 @@ export enum EmbeddedFlowComponentType { /** Consent component for displaying consent purposes and attributes */ Consent = 'CONSENT', + /** Copyable text display component that shows text with a copy-to-clipboard action */ + CopyableText = 'COPYABLE_TEXT', + /** Divider component for visual separation of content */ Divider = 'DIVIDER', @@ -320,6 +323,12 @@ export interface EmbeddedFlowComponent { */ size?: number; + /** + * Data source key for dynamic components (e.g., COPYABLE_TEXT). + * References a key in additionalData whose value is resolved at render time. + */ + source?: string; + /** * Image source URL (for Image components). */ diff --git a/packages/react/src/components/presentation/auth/AcceptInvite/v2/BaseAcceptInvite.tsx b/packages/react/src/components/presentation/auth/AcceptInvite/v2/BaseAcceptInvite.tsx index 7c6624f7..fd2f3dc8 100644 --- a/packages/react/src/components/presentation/auth/AcceptInvite/v2/BaseAcceptInvite.tsx +++ b/packages/react/src/components/presentation/auth/AcceptInvite/v2/BaseAcceptInvite.tsx @@ -56,11 +56,6 @@ export interface AcceptInviteFlowResponse { * Render props for custom UI rendering of AcceptInvite. */ export interface BaseAcceptInviteRenderProps { - /** - * Title from the password screen (for use in completion screen). - */ - completionTitle?: string; - /** * Flow components from the current step. */ @@ -281,7 +276,6 @@ const BaseAcceptInvite: FC = ({ const [formErrors, setFormErrors] = useState>({}); const [touchedFields, setTouchedFields] = useState>({}); const [isFormValid, setIsFormValid] = useState(true); - const [completionTitle, setCompletionTitle] = useState(undefined); const tokenValidationAttemptedRef: any = useRef(false); @@ -348,7 +342,6 @@ const BaseAcceptInvite: FC = ({ currentFlowId: flowId ?? null, isInitialized: true, onComplete: () => { - setIsComplete(true); setIsValidatingToken(false); onComplete?.(); }, @@ -488,21 +481,15 @@ const BaseAcceptInvite: FC = ({ } } - // Store the heading from current flow before completion - if (currentFlow?.data?.components || currentFlow?.data?.meta?.components) { - const currentComponents: any = currentFlow.data.components || currentFlow.data.meta?.components || []; - const heading: any = currentComponents.find( - (comp: any) => comp.type === 'TEXT' && comp.variant === 'HEADING_1', - ); - if (heading?.label) { - setCompletionTitle(heading.label); - } - } - // Check for completion if (response.flowStatus === 'COMPLETE') { setIsComplete(true); - onComplete?.(); + const completionComponents: any[] = response.data?.components || response.data?.meta?.components || []; + if (completionComponents.length > 0) { + setCurrentFlow(response); + } else { + onComplete?.(); + } return; } @@ -632,7 +619,6 @@ const BaseAcceptInvite: FC = ({ // Render props const renderProps: BaseAcceptInviteRenderProps = { - completionTitle, components, error: apiError, fieldErrors: formErrors, @@ -704,33 +690,6 @@ const BaseAcceptInvite: FC = ({ ); } - // Completion state - if (isComplete) { - return ( - - - - Account Setup Complete! - - - - - - Your account has been successfully set up. You can now sign in with your credentials. - - - {onGoToSignIn && ( -
- -
- )} -
-
- ); - } - // Flow components (password form) return ( diff --git a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx index c9c92a0b..210904ea 100644 --- a/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx +++ b/packages/react/src/components/presentation/auth/AuthOptionFactory.tsx @@ -52,6 +52,7 @@ import SignInWithEthereumButton from '../../adapters/SignInWithEthereumButton'; import SmsOtpButton from '../../adapters/SmsOtpButton'; import {createField} from '../../factories/FieldFactory'; import Button from '../../primitives/Button/Button'; +import CopyableText from '../../primitives/CopyableText/CopyableText'; import Divider from '../../primitives/Divider/Divider'; import flowIconRegistry from '../../primitives/Icons/flowIconRegistry'; import Select from '../../primitives/Select/Select'; @@ -581,6 +582,14 @@ const createAuthComponentFromFlow = ( return ; } + case EmbeddedFlowComponentType.CopyableText: { + const sourceKey: string | undefined = (component as any).source; + const value: string = sourceKey && options.additionalData ? String(options.additionalData[sourceKey] ?? '') : ''; + const labelText: string | undefined = resolve((component as any).label) || undefined; + + return ; + } + default: // Gracefully handle unsupported component types by returning null logger.warn(`Unsupported component type: ${component.type}. Skipping render.`); diff --git a/packages/react/src/components/presentation/auth/InviteUser/v2/BaseInviteUser.tsx b/packages/react/src/components/presentation/auth/InviteUser/v2/BaseInviteUser.tsx index 7054ae51..4626f69c 100644 --- a/packages/react/src/components/presentation/auth/InviteUser/v2/BaseInviteUser.tsx +++ b/packages/react/src/components/presentation/auth/InviteUser/v2/BaseInviteUser.tsx @@ -25,7 +25,6 @@ import useTheme from '../../../../../contexts/Theme/useTheme'; import useTranslation from '../../../../../hooks/useTranslation'; import {normalizeFlowResponse, extractErrorMessage} from '../../../../../utils/v2/flowTransformer'; import AlertPrimitive from '../../../../primitives/Alert/Alert'; -import Button from '../../../../primitives/Button/Button'; // eslint-disable-next-line import/no-named-as-default import CardPrimitive, {CardProps} from '../../../../primitives/Card/Card'; import Spinner from '../../../../primitives/Spinner/Spinner'; @@ -63,11 +62,6 @@ export interface BaseInviteUserRenderProps { */ components: any[]; - /** - * Copy invite link to clipboard. - */ - copyInviteLink: () => Promise; - /** * API error (if any). */ @@ -98,26 +92,6 @@ export interface BaseInviteUserRenderProps { */ handleSubmit: (component: any, data?: Record) => Promise; - /** - * Generated invite link (available after user provisioning). - */ - inviteLink?: string; - - /** - * Whether the invite link was copied. - */ - inviteLinkCopied: boolean; - - /** - * Whether the invite email was sent successfully. - */ - isEmailSent: boolean; - - /** - * Whether the invite link has been generated (admin flow complete). - */ - isInviteGenerated: boolean; - /** * Loading state. */ @@ -205,11 +179,6 @@ export interface BaseInviteUserProps { */ onInitialize: (payload: Record) => Promise; - /** - * Callback when the invite link is generated successfully. - */ - onInviteLinkGenerated?: (inviteLink: string, flowId: string) => void; - /** * Function to submit flow step data. * This should make an authenticated request to the flow/execute endpoint. @@ -264,7 +233,6 @@ const BaseInviteUser: FC = ({ onSubmit, onError, onFlowChange, - onInviteLinkGenerated, className = '', children, fetchOrganizationUnitChildren, @@ -286,9 +254,6 @@ const BaseInviteUser: FC = ({ const [formValues, setFormValues] = useState>({}); const [formErrors, setFormErrors] = useState>({}); const [touchedFields, setTouchedFields] = useState>({}); - const [inviteLink, setInviteLink] = useState(); - const [inviteLinkCopied, setInviteLinkCopied] = useState(false); - const [emailSent, setEmailSent] = useState(false); const [isFormValid, setIsFormValid] = useState(true); const initializationAttemptedRef: any = useRef(false); @@ -452,18 +417,6 @@ const BaseInviteUser: FC = ({ const response: any = normalizeFlowResponseLocal(rawResponse); onFlowChange?.(response); - // Check if invite link is in the response - if (response.data?.additionalData?.['inviteLink']) { - const inviteLinkValue: any = response.data.additionalData['inviteLink']; - setInviteLink(inviteLinkValue); - onInviteLinkGenerated?.(inviteLinkValue, response.flowId); - } - - // Check if email was sent successfully - if (response.data?.additionalData?.['emailSent'] === 'true') { - setEmailSent(true); - } - // Check for error status if (response.flowStatus === 'ERROR') { handleError(response); @@ -481,41 +434,9 @@ const BaseInviteUser: FC = ({ setIsLoading(false); } }, - [ - currentFlow, - formValues, - validateForm, - onSubmit, - onFlowChange, - onInviteLinkGenerated, - handleError, - normalizeFlowResponseLocal, - ], + [currentFlow, formValues, validateForm, onSubmit, onFlowChange, handleError, normalizeFlowResponseLocal], ); - /** - * Copy invite link to clipboard. - */ - const copyInviteLink: any = useCallback(async () => { - if (!inviteLink) return; - - try { - await navigator.clipboard.writeText(inviteLink); - setInviteLinkCopied(true); - setTimeout(() => setInviteLinkCopied(false), 3000); - } catch { - // Fallback for browsers that don't support clipboard API - const textArea: any = document.createElement('textarea'); - textArea.value = inviteLink; - document.body.appendChild(textArea); - textArea.select(); - document.execCommand('copy'); - document.body.removeChild(textArea); - setInviteLinkCopied(true); - setTimeout(() => setInviteLinkCopied(false), 3000); - } - }, [inviteLink]); - /** * Reset the flow to invite another user. */ @@ -526,9 +447,6 @@ const BaseInviteUser: FC = ({ setFormValues({}); setFormErrors({}); setTouchedFields({}); - setInviteLink(undefined); - setInviteLinkCopied(false); - setEmailSent(false); initializationAttemptedRef.current = false; }, []); @@ -655,24 +573,17 @@ const BaseInviteUser: FC = ({ const components: any = currentFlow?.data?.components || currentFlow?.data?.meta?.components || []; const {title, subtitle} = extractHeadings(components); const componentsWithoutHeadings: any = filterHeadings(components); - const isInviteGenerated: any = !!inviteLink; - const isEmailSent: boolean = emailSent; // Render props const renderProps: BaseInviteUserRenderProps = { additionalData: currentFlow?.data?.additionalData, components, - copyInviteLink, error: apiError, fieldErrors: formErrors, flowId: currentFlow?.flowId, handleInputBlur, handleInputChange, handleSubmit, - inviteLink, - inviteLinkCopied, - isEmailSent, - isInviteGenerated, isLoading, isValid: isFormValid, meta, @@ -730,80 +641,6 @@ const BaseInviteUser: FC = ({ ); } - // Invite email sent successfully - show email sent confirmation - if (isInviteGenerated && isEmailSent) { - return ( - - - - Invite Email Sent! - - - - - - An invitation email has been sent successfully. The user can complete their registration using the link in - the email. - - -
- -
-
-
- ); - } - - // Invite link generated but email not sent - show copy link fallback - if (isInviteGenerated && inviteLink) { - return ( - - - - Invite Link Generated! - - - - - - Share this link with the user to complete their registration. - - -
- - Invite Link - -
- - {inviteLink} - - -
-
-
- -
-
-
- ); - } - // Flow components return ( diff --git a/packages/react/src/components/presentation/auth/InviteUser/v2/InviteUser.tsx b/packages/react/src/components/presentation/auth/InviteUser/v2/InviteUser.tsx index 041cd09b..e40d9ec1 100644 --- a/packages/react/src/components/presentation/auth/InviteUser/v2/InviteUser.tsx +++ b/packages/react/src/components/presentation/auth/InviteUser/v2/InviteUser.tsx @@ -52,11 +52,6 @@ export interface InviteUserProps { */ onFlowChange?: (response: InviteUserFlowResponse) => void; - /** - * Callback when the invite link is generated successfully. - */ - onInviteLinkGenerated?: (inviteLink: string, flowId: string) => void; - /** * Whether to show the subtitle. */ @@ -119,7 +114,6 @@ export interface InviteUserProps { * ``` */ const InviteUser: FC = ({ - onInviteLinkGenerated, onError, onFlowChange, className, @@ -197,7 +191,6 @@ const InviteUser: FC = ({ => + useMemo( + () => ({ + container: css` + display: flex; + flex-direction: column; + gap: calc(${theme.vars.spacing.unit} * 0.5); + width: 100%; + `, + copyButton: css` + flex-shrink: 0; + white-space: nowrap; + `, + label: css` + color: ${theme.vars.colors.text.secondary}; + font-size: 0.875rem; + font-weight: 500; + `, + valueBox: css` + align-items: center; + background-color: ${theme.vars.colors.background.surface}; + border: 1px solid ${theme.vars.colors.border}; + border-radius: ${theme.vars.borderRadius.small}; + display: flex; + gap: calc(${theme.vars.spacing.unit} * 1); + padding: calc(${theme.vars.spacing.unit} * 0.75) calc(${theme.vars.spacing.unit} * 1); + `, + valueText: css` + color: ${theme.vars.colors.text.primary}; + flex: 1; + font-family: monospace; + font-size: 0.85rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + word-break: break-all; + `, + }), + [theme], + ); + +export default useStyles; diff --git a/packages/react/src/components/primitives/CopyableText/CopyableText.tsx b/packages/react/src/components/primitives/CopyableText/CopyableText.tsx new file mode 100644 index 00000000..fa25b0a8 --- /dev/null +++ b/packages/react/src/components/primitives/CopyableText/CopyableText.tsx @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {FC, ReactElement, useCallback, useState} from 'react'; +import useStyles from './CopyableText.styles'; +import useTheme from '../../../contexts/Theme/useTheme'; +import useTranslation from '../../../hooks/useTranslation'; +import Button from '../Button/Button'; + +export interface CopyableTextProps { + /** + * Optional label displayed above the value box. + */ + label?: string; + /** + * The text value to display and copy. + */ + value: string; +} + +/** + * A React component that displays a text value with an optional label and a button to copy the value to + * the clipboard. When the button is clicked, it attempts to copy the value using the Clipboard API, and + * falls back to a textarea method if the API is not supported. + * After copying, it shows a "Copied!" message for 3 seconds before resetting. + */ +const CopyableText: FC = ({label, value}: CopyableTextProps): ReactElement => { + const {theme} = useTheme(); + const styles: Record = useStyles(theme); + const {t} = useTranslation(); + const [copied, setCopied] = useState(false); + + const handleCopy: ReturnType = useCallback(async (): Promise => { + try { + await navigator.clipboard.writeText(value); + } catch { + const textArea: HTMLTextAreaElement = document.createElement('textarea'); + textArea.value = value; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand('copy'); + document.body.removeChild(textArea); + } + setCopied(true); + setTimeout(() => setCopied(false), 3000); + }, [value]); + + return ( +
+ {label && {label}} +
+ {value} + +
+
+ ); +}; + +export default CopyableText; diff --git a/packages/react/src/components/primitives/CopyableText/index.ts b/packages/react/src/components/primitives/CopyableText/index.ts new file mode 100644 index 00000000..28f371c8 --- /dev/null +++ b/packages/react/src/components/primitives/CopyableText/index.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export {default} from './CopyableText'; +export type {CopyableTextProps} from './CopyableText'; From 7e8151d68786d53566502a1a164428635a803ec8 Mon Sep 17 00:00:00 2001 From: ThaminduDilshan Date: Thu, 9 Apr 2026 00:37:14 +0530 Subject: [PATCH 2/2] =?UTF-8?q?chore:=20add=20changeset=20=F0=9F=A6=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/orange-spies-refuse.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/orange-spies-refuse.md diff --git a/.changeset/orange-spies-refuse.md b/.changeset/orange-spies-refuse.md new file mode 100644 index 00000000..3e96ab53 --- /dev/null +++ b/.changeset/orange-spies-refuse.md @@ -0,0 +1,7 @@ +--- +'@asgardeo/javascript': patch +'@asgardeo/react': patch +'@asgardeo/i18n': patch +--- + +Add flow native render support for invite flows removing the custom workarounds