Skip to content

fix(cvc): fall back to short "CVC" label for French locale in narrow fields - #1736

Open
AbhishekChorotiya wants to merge 1 commit into
mainfrom
fix/cvc-label-fallback-narrow-field
Open

fix(cvc): fall back to short "CVC" label for French locale in narrow fields#1736
AbhishekChorotiya wants to merge 1 commit into
mainfrom
fix/cvc-label-fallback-narrow-field

Conversation

@AbhishekChorotiya

@AbhishekChorotiya AbhishekChorotiya commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

Closes #1735

The full French CVC label ("Code CVC") was getting clipped in narrow containers, because it is longer than the English abbreviation ("CVC"). This adds a French-only fallback: when the field is too narrow to fit "Code CVC", the widget shows the short "CVC" label instead, and restores the full label when the field is widened again.

Approach

  • French-only. The fallback is scoped to the French (fr) locale, because it is the only locale that ships a long CVC label — every other locale already renders a short label (e.g. fr-BE already uses CVC). Detection is localeString.locale == "fr", the normalized locale code from the resolved locale file, so it reliably matches fr, fr-FR, FR, and auto → French. No per-locale string or shared-type changes are required.
  • ResizeObserver-driven. A new reusable useResizeObserver hook (src/Hooks/UseResizeObserver.res) observes the CVC field container, so the label choice stays correct across the element's mount, its internal layout changes, and any real container resize (and reverts to the full label when there is room again). The observer only runs when isFrenchCvc && !isSavedCardCvcFlow. The existing ResizeObserver type/binding in src/ResizeObserver.res is reused unchanged (the hook calls ResizeObserver.newResizerObserver), so its current consumers are untouched.
  • Canvas measurement. The label's natural width is measured with Canvas measureText using the label's computed font. This is necessary because the default floating label is absolutely positioned and wraps, so scrollWidth cannot detect the horizontal overflow; it is also cheaper than DOM measurement (no reflow, no hidden node). The natural width is compared against the container's clientWidth with a small buffer (clientWidth - 24).
  • PaymentInputField stays generic. It gains a single optional ~fieldContainerRef prop and has no CVC/locale knowledge; the CVC-specific logic lives entirely in CardCVCElement.

How did you test it?

Screen.Recording.2026-09-02.at.6.41.41.PM.mov

Manually verified in the demo app against a standalone CardCVCElement rendered in a resizable container, using the local SDK build (Playwright-driven):

  • ?locale=fr, narrow field (≈52px) → label shows "CVC" and stays stable (no flicker back to "Code CVC" across the element's remount/layout transitions).
  • ?locale=fr, wide field (≈292px) → label shows "Code CVC"; shrinking it back to ≈52px → falls back to "CVC" (bidirectional).
  • ?locale=en → unaffected (no French fallback engaged).
  • npm run re:build passes.

Checklist

  • I ran npm run re:build
  • I reviewed submitted code
  • I added unit tests for my changes where possible

@semanticdiff-com

Copy link
Copy Markdown

Review changes with  SemanticDiff

@XyneSpaces

Copy link
Copy Markdown

[should-fix] Move the onResizeRef.current = onResize assignment into a useEffect.

Mutating a ref during render is a React side-effect and risks stale closures or tearing in concurrent rendering. The observer callback should call the latest closure, but the ref update itself belongs inside an effect so render stays pure.

// src/Hooks/ResizeObserver.res
let useResizeObserver = (
  ~elementRef: React.ref<Nullable.t<Dom.element>>,
  ~enabled=true,
  ~refreshKey="",
  ~onResize: unit => unit,
) => {
  let onResizeRef = React.useRef(onResize)

  React.useEffect(() => {
    onResizeRef.current = onResize
    None
  }, [onResize])

  React.useEffect(() => {
    if enabled {
      let observer = newResizerObserver(_ => onResizeRef.current())
      switch elementRef.current->Nullable.toOption {
      | Some(el) =>
        onResizeRef.current()
        observer.observe(el)
      | None => ()
      }
      Some(() => observer.disconnect())
    } else {
      None
    }
  }, (enabled, refreshKey))
}

@AbhishekChorotiya AbhishekChorotiya changed the title fix: fall back to short CVC label when field is too narrow fix: fall back to short CVC label for French locale when field is too narrow Sep 2, 2026
@AbhishekChorotiya
AbhishekChorotiya force-pushed the fix/cvc-label-fallback-narrow-field branch from f3cde5b to df09c8e Compare September 2, 2026 12:38
@AbhishekChorotiya AbhishekChorotiya changed the title fix: fall back to short CVC label for French locale when field is too narrow fix: fall back to short CVC label for French locale in narrow fields Sep 2, 2026
@AbhishekChorotiya
AbhishekChorotiya force-pushed the fix/cvc-label-fallback-narrow-field branch from df09c8e to beca2a3 Compare September 2, 2026 12:43
@AbhishekChorotiya
AbhishekChorotiya force-pushed the fix/cvc-label-fallback-narrow-field branch from beca2a3 to 3d58cce Compare September 2, 2026 12:47
@AbhishekChorotiya
AbhishekChorotiya force-pushed the fix/cvc-label-fallback-narrow-field branch from 3d58cce to cbc3e9a Compare September 2, 2026 12:51
@AbhishekChorotiya
AbhishekChorotiya force-pushed the fix/cvc-label-fallback-narrow-field branch from cbc3e9a to 8c47b60 Compare September 2, 2026 12:53
The full French CVC label ("Code CVC") was getting clipped in narrow
containers. Add a French-only fallback to the short "CVC" label when the
field is too narrow, restoring the full label when it widens again.

- Scope the fallback to the French ("fr") locale only; every other locale
  already ships a short CVC label, so no per-locale string/type changes are
  needed.
- Add a reusable useResizeObserver hook in src/Hooks that observes the field
  container, so the decision stays correct across mounts, layout changes and
  resizes.
- Measure the label's natural width with canvas measureText (the floating
  label is absolutely positioned and wraps, so scrollWidth cannot detect the
  overflow); compare against the container width with a small buffer.
- Keep PaymentInputField generic via a new optional ~fieldContainerRef prop;
  the CVC-specific logic lives in CardCVCElement.

Closes #1735
@AbhishekChorotiya
AbhishekChorotiya force-pushed the fix/cvc-label-fallback-narrow-field branch from 8c47b60 to 9d1db0e Compare September 2, 2026 12:54
@AbhishekChorotiya AbhishekChorotiya changed the title fix: fall back to short CVC label for French locale in narrow fields fix(cvc): fall back to short "CVC" label for French locale in narrow fields Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CVC widget label is clipped in narrow containers (e.g. French "Code CVC")

3 participants