Added prefix and postfix support in react sdk.#27
Conversation
📝 WalkthroughWalkthroughChangesAffixed input support
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant EmbeddedFlow
participant AuthOptionFactory
participant AffixedField
participant AuthSubmit
participant composeAffixedInputs
EmbeddedFlow->>AuthOptionFactory: provide prefixes and postfix
AuthOptionFactory->>AffixedField: render affixed input
AffixedField->>AuthOptionFactory: update typed and affix state
AuthSubmit->>composeAffixedInputs: compose form data
composeAffixedInputs-->>AuthSubmit: return combined inputs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/javascript/src/models/embedded-flow.ts`:
- Around line 515-525: Correct the JSDoc on the public PrefixOption interface:
mark label as required, replace the misleading icon-URL comment with
documentation describing the optional maxLength number, and add a comment
explaining the optional regex string. Keep the interface fields and types
unchanged.
In `@packages/react/src/components/presentation/auth/AuthOptionFactory.tsx`:
- Around line 271-304: The postfix-only path in the AuthOptionFactory
AffixedField rendering does not display the configured postfix even though
submission uses it. Extend AffixedField to accept and render a postfix value,
then pass component.postfix from this branch while preserving the existing
prefix behavior.
- Around line 282-292: Update the AffixedField invocation in AuthOptionFactory
to pass through component.id and component.classes, matching the corresponding
regular field configuration. Preserve all existing affixed-field props while
ensuring configured styling and field identification are retained.
In
`@packages/react/src/components/primitives/AffixedField/AffixedField.styles.ts`:
- Line 37: Update the borderRadius assignment in AffixedField styles to use
nullish coalescing instead of logical OR, preserving an explicit 0 value while
still falling back for null or undefined.
- Around line 66-69: Update the focus styles in AffixedField.styles.ts to avoid
concatenating `20` onto the CSS-variable-based `focusColor`; use the existing
alpha-safe color helper for the focus ring. Apply the same change to the prefix
select focus state so both focus selectors produce valid box-shadow colors.
In `@packages/react/src/components/primitives/AffixedField/index.ts`:
- Around line 1-2: Add the standard WSO2 Apache 2.0 copyright header at the top
of the AffixedField module, before its export statements, matching the header
format used by other new files in the repository.
In `@packages/react/src/utils/composeAffixedInputs.ts`:
- Around line 24-42: Update AFFIX_PREFIX_SENTINEL, AFFIX_POSTFIX_SENTINEL,
affixPrefixKey, and affixPostfixKey to derive the runtime namespace through
getVendorPrefix(vendor) instead of hardcoded __thunderid_*__ values. Add the
vendor configuration parameter to both key helpers and ensure all callers pass
and use the configured vendor when reading or generating affix keys.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: c1d6867a-b92e-4a41-a767-8ef06c7fa8d2
📒 Files selected for processing (10)
packages/javascript/src/index.tspackages/javascript/src/models/embedded-flow.tspackages/react/src/components/presentation/auth/AuthOptionFactory.tsxpackages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsxpackages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsxpackages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsxpackages/react/src/components/primitives/AffixedField/AffixedField.styles.tspackages/react/src/components/primitives/AffixedField/AffixedField.tsxpackages/react/src/components/primitives/AffixedField/index.tspackages/react/src/utils/composeAffixedInputs.ts
63bea21 to
c3b2074
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx (1)
448-455: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider using
Object.entriesfor consistency withBaseRecovery.
BaseRecoveryfilters composed inputs viaObject.entries(composedData).forEach(([key, value]) => ...), while this file usesObject.keys(composedData).forEach((key) => ... composedData[key] ...). Both are functionally equivalent, but aligning on one approach reduces cognitive overhead when maintaining both auth flows side by side.♻️ Optional refactor for consistency
const filteredInputs: Record<string, any> = {}; if (composedData) { - Object.keys(composedData).forEach((key: any) => { - if (composedData[key] !== undefined && composedData[key] !== null && composedData[key] !== '') { - filteredInputs[key] = composedData[key]; + Object.entries(composedData).forEach(([key, value]: [string, any]) => { + if (value !== null && value !== undefined && value !== '') { + filteredInputs[key] = value; } }); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx` around lines 448 - 455, Update the composed-input filtering in BaseSignIn to iterate with Object.entries(composedData), destructuring each key and value like BaseRecovery. Preserve the existing exclusion of undefined, null, and empty-string values and the resulting filteredInputs contents.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/react/src/components/presentation/auth/AuthOptionFactory.tsx`:
- Around line 265-311: Update the AffixedField onChange handler to initialize
missing prefixStateKey and postfixStateKey entries before or alongside updating
the field value, using defaultPrefixValue and component.postfix when configured.
Keep the existing onFocus initialization and ensure autofilled changes create
the sentinel keys so composeAffixedInputs submits the affixed value.
In `@packages/react/src/components/primitives/AffixedField/AffixedField.tsx`:
- Around line 96-108: Update renderPrefix and the associated input accessibility
props so the fixed prefix remains announced to screen readers while the visual
prefix span stays aria-hidden. Add a visually hidden announcement or
aria-describedby relationship containing the prefix value (such as +1), using
the component’s existing styling/utilities where available, and ensure it
applies to the submitted input context.
---
Nitpick comments:
In `@packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx`:
- Around line 448-455: Update the composed-input filtering in BaseSignIn to
iterate with Object.entries(composedData), destructuring each key and value like
BaseRecovery. Preserve the existing exclusion of undefined, null, and
empty-string values and the resulting filteredInputs contents.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: ff347b51-ac46-4e48-b263-330e032e940d
📒 Files selected for processing (10)
packages/javascript/src/index.tspackages/javascript/src/models/embedded-flow.tspackages/react/src/components/presentation/auth/AuthOptionFactory.tsxpackages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsxpackages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsxpackages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsxpackages/react/src/components/primitives/AffixedField/AffixedField.styles.tspackages/react/src/components/primitives/AffixedField/AffixedField.tsxpackages/react/src/components/primitives/AffixedField/index.tspackages/react/src/utils/composeAffixedInputs.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/javascript/src/index.ts
- packages/react/src/components/primitives/AffixedField/index.ts
- packages/react/src/components/primitives/AffixedField/AffixedField.styles.ts
- packages/javascript/src/models/embedded-flow.ts
c3b2074 to
ffb423b
Compare
Signed-off-by: sajid.mannikeri <sajid.mannikeri@infosys.com>
ffb423b to
7062068
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx (1)
443-452: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSame compose-then-filter logic duplicated in three submit handlers.
BaseSignIn.tsx,BaseSignUp.tsx, andBaseRecovery.tsxeach independently callcomposeAffixedInputs(data, vendor)and then loop to dropnull/undefined/''values into afilteredInputsobject. Extracting this into a single exported helper (e.g.composeAndFilterAffixedInputs(data, vendor)incomposeAffixedInputs.ts) would remove the triplication and give one place to fix/extend this behavior later.
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx#L443-L452: replace the inline compose+filter block with a call to the new shared helper.packages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsx#L800-L807: replace the inline compose+filter block with a call to the new shared helper.packages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsx#L314-L320: replace the inline compose+filter block with a call to the new shared helper.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx` around lines 443 - 452, Extract the shared compose-and-filter behavior into an exported helper such as composeAndFilterAffixedInputs in packages/react/src/components/presentation/auth/composeAffixedInputs.ts, preserving removal of undefined, null, and empty-string values. Replace the duplicated inline logic in packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx:443-452, packages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsx:800-807, and packages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsx:314-320 with calls to the helper and update imports accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx`:
- Around line 443-452: Extract the shared compose-and-filter behavior into an
exported helper such as composeAndFilterAffixedInputs in
packages/react/src/components/presentation/auth/composeAffixedInputs.ts,
preserving removal of undefined, null, and empty-string values. Replace the
duplicated inline logic in
packages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsx:443-452,
packages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsx:800-807,
and
packages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsx:314-320
with calls to the helper and update imports accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a1cf51f5-b88e-4f10-8176-e02dd7d0b63c
📒 Files selected for processing (10)
packages/javascript/src/index.tspackages/javascript/src/models/embedded-flow.tspackages/react/src/components/presentation/auth/AuthOptionFactory.tsxpackages/react/src/components/presentation/auth/Recovery/BaseRecovery.tsxpackages/react/src/components/presentation/auth/SignIn/BaseSignIn.tsxpackages/react/src/components/presentation/auth/SignUp/BaseSignUp.tsxpackages/react/src/components/primitives/AffixedField/AffixedField.styles.tspackages/react/src/components/primitives/AffixedField/AffixedField.tsxpackages/react/src/components/primitives/AffixedField/index.tspackages/react/src/utils/composeAffixedInputs.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/javascript/src/index.ts
- packages/react/src/components/primitives/AffixedField/index.ts
- packages/react/src/components/primitives/AffixedField/AffixedField.styles.ts
- packages/javascript/src/models/embedded-flow.ts
- packages/react/src/utils/composeAffixedInputs.ts
Purpose
Adds prefix and postfix support to text-family login-id inputs (
TEXT_INPUT,EMAIL_INPUT,PASSWORD_INPUT,PHONE_INPUT) rendered by the SDK from an embedded flow response. Prefixes render as either a fixed leading span (single option) or a dropdown (multiple options); postfix is silently appended to the submitted value and never rendered.Example flow component now supported end-to-end:
Typed
9876598765with+855selected is submitted as+8559876598765@phone.Approach
1. Contract additions (
@thunderid/javascript)PrefixOption { label, value, maxLength?, regex? }.EmbeddedFlowComponent:postfix?: stringandprefixes?: string | PrefixOption[]. The polymorphic prefixes shape mirrors the develop-branch schema (single static string OR selectable list). All additions are additive and optional — existing flows are unaffected.2. New primitive
AffixedField(@thunderid/react)TextField/PasswordField. Acceptstypeprop, so the same primitive backs text/email/password/tel inputs.prefixes(string → single entry) so render logic works from a uniformPrefixOption[]. Renders a fixed span for 0–1 entries and a<select>for 2+. Postfix is intentionally not rendered.TextField) to avoid bloating a widely-used base component with a feature only some flows need.3. Routing lifted in
AuthOptionFactoryTEXT_INPUT,EMAIL_INPUT,PASSWORD_INPUT,PHONE_INPUT) are merged into one block.AffixedFieldwhenprefixesorpostfixis present; otherwise the existingcreateFieldpath runs unchanged. Flows that don't opt in walk the identical pre-change code path.4. Submit-time composition (
composeAffixedInputs)useForm's flat value map via namespaced sentinel keys (__thunderid_prefix__<id>,__thunderid_postfix__<id>). These are seeded lazily ononFocusto avoid render-time side effects.composeAffixedInputs(formValues)runs insideBaseSignIn/BaseSignUp/BaseRecoveryjust before the parentonSubmit, rewriting each affixed identifier to${prefix}${typed}${postfix}and stripping sentinel keys.useFormis not modified — composition is a transform on the outbound payload only.5. Backward compatibility
PrefixOptiontype. Internal renames (PhoneField→AffixedField,composePhoneInputs→composeAffixedInputs) are invisible to SDK consumers — neither symbol was ever exported.prefixes/postfixis byte-identical to prior behavior.Deferred (follow-up): per-prefix
maxLength/regexare carried inPrefixOptionbut not yet wired into the form validator, which would require making the field validator reactive to the currently selected prefix. Tracked as a separate change.Related Issues
Related PRs
Checklist
breaking changelabel added.Security checks
Summary by CodeRabbit
Summary
AffixedFieldprimitive for rendering affixed inputs with consistent styling and accessibility.PrefixOptiontype to the public TypeScript API.