Skip to content

Conversation

@OnurVar
Copy link
Contributor

@OnurVar OnurVar commented Oct 29, 2025

Description

ACC-5719

Summary

Refactor CheckoutComponents to use a design token system and consolidate input field components for
pixel-perfect Figma implementation.

Changes

Design Token System

  • JSON-based token definitions (base + dark mode)
  • Type-safe Swift code generation from tokens
  • Light/dark mode support with automatic switching
  • Consistent spacing, sizing, and color values

Component Refactoring

  • PrimerInputFieldContainer - Unified container for all inputs
  • CardNetworkBadge - Extracted reusable component
  • UITextField Extensions - Shared styling utilities
  • Pixel-perfect heights matching Figma designs

Font System

  • InterVariable font integration
  • Optimized loading with caching
  • DEBUG conditionals for SwiftUI previews

Benefits

  • Eliminates hardcoded values throughout codebase
  • Single source of truth for design specifications
  • Easy theme customization via token overrides
  • Consistent UI across all input components

Technical Implementation

  • Token system in DesignTokens/ with JSON source files
  • Generated Swift code in Internal/Tokens/
  • Reusable input container in Presentation/Components/Containers/
  • Shared styling utilities in Presentation/Components/Utilities/

Testing

  • All existing tests pass
  • Verified light/dark mode switching
  • Validated pixel-perfect dimensions against Figma
  • Tested font loading and fallback behavior

@OnurVar OnurVar force-pushed the ov/feat/pixel-perfect-checkout-components branch from a1598dc to 16f1972 Compare October 29, 2025 23:27
@github-actions
Copy link
Contributor

github-actions bot commented Oct 29, 2025

Warnings
⚠️ > Pull Request size seems relatively large. If this Pull Request contains multiple changes, please split each into separate PR will helps faster, easier review.

Generated by 🚫 Danger Swift against 935ec59

@github-actions
Copy link
Contributor

github-actions bot commented Oct 29, 2025

@OnurVar OnurVar force-pushed the ov/feat/pixel-perfect-checkout-components branch from 3797385 to 990551b Compare October 30, 2025 12:57
@OnurVar OnurVar changed the title Ov/feat/pixel perfect checkout components refactor: Implement design tokens and pixel-perfect input UI Oct 30, 2025
@OnurVar OnurVar self-assigned this Oct 30, 2025
@OnurVar OnurVar force-pushed the ov/feat/pixel-perfect-checkout-components branch from 990551b to f08ddd3 Compare October 30, 2025 13:05
@OnurVar OnurVar marked this pull request as ready for review October 30, 2025 13:06
@OnurVar OnurVar requested review from a team as code owners October 30, 2025 13:06
Copy link
Contributor

@borisprimer borisprimer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work! Few minor things to look at...


#if DEBUG
@available(iOS 15.0, *)
struct CardNetworkBadge_Previews: PreviewProvider {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing job adding all these previews!

.aspectRatio(contentMode: .fit)
.frame(width: iconSize, height: iconSize)
.foregroundColor(PrimerCheckoutColors.iconNegative(tokens: tokens))
.offset(x: hasError ? 0 : -10)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic numbers

Comment on lines 125 to 128
.offset(y: hasError ? 0 : -10)
.opacity(hasError ? 1.0 : 0.0)
.padding(.top, hasError ? PrimerSpacing.xsmall(tokens: tokens) : 0)
.animation(.spring(response: 0.3, dampingFraction: 0.7), value: hasError)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic numbers... can we somehow centralize this animation for future reuse?

forResource: fontNameWithoutExt,
withExtension: "ttf"
) else {
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Font loading failures are silently ignored.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other places as well


/// Generic container for Primer input fields that provides consistent styling, layout, and error handling
@available(iOS 15.0, *)
struct PrimerInputFieldContainer<Content: View, RightContent: View>: View {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observation: Good use of generics, but the RightContent type is optional. Consider using a different pattern:

// Alternative approach
struct PrimerInputFieldContainer<Content: View>: View {
let rightComponent: (() -> AnyView)?
}

This would simplify the type signature when RightContent isn't needed.

Comment on lines 1 to 7
//
// CardNetworkBadge.swift
// PrimerSDK - CheckoutComponents
//
// Created by Boris on 16.7.25.
//

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@henry-cooper-primer is there a way to standardize these headers for all team members?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just AI, marking everything as 'Created by Boris' 😂 I will remove those in the next commit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am referring to this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep should be a swift format rule - added

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was created long before the Swift Format. It's a good point, Semir. Can we add the ticket to unify these in CheckoutComponents @OnurVar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve created the task and will handle these headers separately.

@henry-cooper-primer henry-cooper-primer force-pushed the ov/feat/pixel-perfect-checkout-components branch from e4587de to d4c9da6 Compare November 5, 2025 11:46
OnurVar and others added 6 commits November 5, 2025 19:32
Replace hardcoded values with token-based design system and
consolidate input components for pixel-perfect Figma implementation.

Design System:
- Add DesignTokens with light/dark mode JSON configurations
- Implement token generator and processor for type-safe access
- Add InterVariable font with optimized loading
- Support dynamic appearance mode switching

Component Refactoring:
- Create PrimerInputFieldContainer for consistent input styling
- Extract CardNetworkBadge as reusable component
- Add UITextField styling extensions for shared behavior
- Consolidate all input fields to use container pattern
- Apply pixel-perfect height constraints matching Figma

Technical Details:
- Token system generates Swift code from JSON definitions
- Container provides unified error handling and layout
- Font registration uses DEBUG conditionals for preview support
- All input components share consistent padding and spacing
- Design tokens support theme overrides and customization

This establishes the foundation for scalable, design-driven UI
development with consistent styling across all components.
Font loading failures were previously silently ignored. Added error
logging for all failure points and fixed memory leak in error
handling.
Split container into focused files for better maintainability:
- Core struct and convenience initializer in main file
- View rendering logic in +Rendering extension
- Styling properties in +Styling extension
- Preview helpers in +PreviewHelpers extension

Updated preview format to use #Preview macro and changed access
control to internal to support multi-file organization.
@OnurVar OnurVar force-pushed the ov/feat/pixel-perfect-checkout-components branch from d4c9da6 to a0b503d Compare November 5, 2025 16:35
Simplifies color system naming by removing redundant Primer prefix.
Updates all references across CheckoutComponents module.
Replace custom headers with standard Primer SDK copyright format
in 5 internal CheckoutComponents files to pass CI linting checks.

Files updated:
- PrimerLayout.swift
- MockCardFormScope.swift
- MockDIContainer.swift
- MockDesignTokens.swift
- MockValidationService.swift

// MARK: - Body

@ViewBuilder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is view builder by default


#if DEBUG
@available(iOS 15.0, *)
struct CardNetworkBadge_Previews: PreviewProvider {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use modern preview macros?

#if DEBUG
@available(iOS 15.0, *)
struct PreviewContainer: View {
let label: String?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these can be private

self.label = label
self.text = text
self.errorMessage = errorMessage
self._currentText = State(initialValue: text)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use wrappedValue (they do the same thing but initialValue is technically legacy. Same elsewhere

isSecureTextEntry: false
)

/// Configuration for email input
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please can we avoid these types of comments?

autocorrectionType: .no,
textContentType: .emailAddress,
returnKeyType: .done,
isSecureTextEntry: false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since there are default values in the initialiser, can we make use of them here and elsewhere so we can slim down these properties

@available(iOS 15.0, *)
extension UITextField {
/// Configures the text field with Primer design tokens and standard settings
func configurePrimerStyle(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably slightly too long, I might consider breaking this up into two or three methods

let doneButton = UIButton(type: .system)
doneButton.setTitle("Done", for: .normal)
doneButton.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .medium)
if let target = doneButtonTarget {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use shorthand syntax here

@OnurVar
Copy link
Contributor Author

OnurVar commented Nov 6, 2025

@henry-cooper-primer All review comments have been addressed.

- Use modern #Preview macros instead of PreviewProvider
- Make preview helper properties private
- Use wrappedValue instead of initialValue for State
- Remove redundant comments
- Simplify configuration properties with default values
- Refactor configurePrimerStyle into focused helper methods
- Use Swift shorthand syntax for optional binding (if let x)
@OnurVar OnurVar force-pushed the ov/feat/pixel-perfect-checkout-components branch from f739563 to 935ec59 Compare November 6, 2025 23:12
@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 6, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
1.5% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

5 participants