MCPcopy Index your code
hub / github.com/AppAndFlow/react-native-transformer-text-input

github.com/AppAndFlow/react-native-transformer-text-input @v0.4.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.4.1 ↗ · + Follow
124 symbols 235 edges 50 files 0 documented · 0% updated 7d agov0.4.1 · 2026-06-19★ 1713 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

react-native-transformer-input by App&Flow

TextInput component that allows transforming text synchronously with a worklet.

About

App & Flow is a Montreal-based React Native engineering and consulting studio. We partner with the world’s top companies and are recommended by Expo. Need a hand? Let’s build together. team@appandflow.com

Demo

https://github.com/user-attachments/assets/b22041b2-f5c1-4b2a-9fd0-960d7f5b3cf9

Motivation

Transforming input as users type is common — phone numbers, credit cards, usernames. Existing approaches have trade-offs:

Pattern-based masking (e.g., react-native-advanced-input-mask) uses declarative patterns like +1 ([000]) [000]-[0000]. This works well for fixed formats, but patterns can't express conditional logic, variable-length formats, or transformations that depend on context.

Controlled inputs (value + onChangeText + state) give you full JS flexibility, but create a native → JS → re-render → native round-trip. This causes visible lag and cursor flicker—the input feels sluggish because keystrokes are corrected asynchronously.

This library combines JS flexibility with synchronous execution. Your transform runs as a worklet on the UI thread — no bridge delay, no flicker. Write any logic you need with the responsiveness of a native input.

Installation

npm install react-native-transformer-text-input

Usage

import { useRef } from 'react';
import {
  Transformer,
  TransformerTextInput,
  type TransformerTextInputInstance,
} from 'react-native-transformer-text-input';

// Transformer that formats input as a lowercase username with @ prefix
const usernameTransformer = new Transformer(({ value }) => {
  'worklet';

  const cleaned = value.replace(/[^0-9a-zA-Z]/g, '').toLowerCase();
  return { value: cleaned ? '@' + cleaned : '' };
});

function UsernameTextInput() {
  const inputRef = useRef<TransformerTextInputInstance>(null);

  const handleSubmit = () => {
    const username = inputRef.current?.getValue();
    console.log('Submitted:', username);
  };

  return (
    <TransformerTextInput
      ref={inputRef}
      transformer={usernameTransformer}
      placeholder="@username"
      autoCapitalize="none"
      autoCorrect={false}
      onSubmitEditing={handleSubmit}
    />
  );
}

API

Transformer

Create a transformer by passing a worklet function:

  • Constructor: new Transformer(worklet)
  • worklet input: an object with
  • value: current text value.
  • previousValue: previous text value (falls back to value on first call).
  • selection: current selection { start, end }.
  • previousSelection: previous selection { start, end } (falls back to selection on first call).
  • worklet return:
  • Return null or undefined to apply no transform.
  • Return an object where each field can also be null or undefined to leave that part unchanged:
    • value?: string | null to update the text.
    • selection?: { start: number; end: number } | null to update the selection.

TransformerTextInput

TransformerTextInput wraps React Native TextInput and applies a Transformer on the UI thread.

  • Props: all TextInput props (except value) plus:
  • transformer: a Transformer instance.
  • Ref: TransformerTextInputInstance with:
  • getValue(): string - Returns the current text value.
  • update(options): void - Programmatically update the input.
    • options.value: string - The new text value.
    • options.selection?: { start: number; end: number } - Optional cursor/selection position.
    • options.transform?: boolean - Whether to run the transformer on the new value (default: true).
  • clear(): void - Clear the input value.

Notes

  • The transformer must be a worklet; the Transformer constructor will throw if it isn't.
  • Prefer creating Transformer instances at module scope to avoid recreating worklets on every render.
  • This library supports the New Architecture only.

Selection Control

Selection control is needed because transforms can insert or remove characters, which would otherwise move the cursor unpredictably. The transformer can return a selection to fully control the caret/selection after a change.

Default behavior when no selection is returned: - If the cursor was at the end, it stays at the end. - If the cursor was in the middle, it moves forward by the number of inserted/removed characters. - If the position is ambiguous, it falls back to the end.

Built-in Transformers (Experimental)

Warning: Built-in transformers are experimental. Breaking changes may occur in minor versions.

The library includes ready-to-use transformers for common use cases.

PatternTransformer

Formats input using a pattern string with placeholder characters.

import { PatternTransformer } from 'react-native-transformer-text-input/formatters/pattern';

const dateTransformer = new PatternTransformer({
  pattern: '##/##/####',  // # = digit, A = letter, * = alphanumeric
});

// Formats as: 12/31/2024
<TransformerTextInput
  transformer={dateTransformer}
  keyboardType="number-pad"
/>

Options: - pattern: Pattern string where # matches digits, A matches letters, * matches alphanumeric. - definitions: Custom placeholder definitions (e.g., { 'X': /[0-9A-F]/i } for hex). - showTrailingLiterals: Show literal characters after the last input (default: false).

PhoneNumberTransformer

Formats phone numbers as the user types.

import { PhoneNumberTransformer } from 'react-native-transformer-text-input/formatters/phone-number';

const phoneTransformer = new PhoneNumberTransformer({
  country: 'US',
  debug: false,            // Enable debug logging (default: false)
});

// Formats as: +1 (555) 123-4567
<TransformerTextInput
  transformer={phoneTransformer}
  keyboardType="phone-pad"
/>

Acknowledgments

Contributing

License

MIT


Made with create-react-native-library

Extension points exported contracts — how you extend this code

Spec (Interface)
(no doc) [1 implementers]
src/NativeTransformerTextInputModule.ts
NativeProps (Interface)
(no doc)
src/TransformerTextInputDecoratorViewNativeComponent.ts
PhoneFormat (Interface)
(no doc)
scripts/generate-phone-data.ts
NativeCommands (Interface)
(no doc)
src/TransformerTextInputDecoratorViewNativeComponent.ts
CountryPhoneData (Interface)
(no doc)
scripts/generate-phone-data.ts

Core symbols most depended-on inside this repo

registerTransformer
called by 6
src/registry.ts
computeUncontrolledSelection
called by 6
src/selection.ts
validateSelection
called by 6
src/selection.ts
update
called by 5
android/src/main/java/com/appandflow/transformertextinput/TransformerTextInputDecoratorView.kt
positionAfterNChars
called by 5
src/formatters/pattern.ts
detectCountry
called by 4
src/formatters/phone-number.ts
extractDigits
called by 4
src/formatters/phone-number.ts
countDigitsBefore
called by 4
src/formatters/phone-number.ts

Shape

Function 55
Method 42
Class 22
Interface 5

Languages

TypeScript60%
Kotlin25%
C++15%

Modules by API surface

src/formatters/phone-number.ts14 symbols
android/src/main/java/com/appandflow/transformertextinput/TransformerTextInputDecoratorView.kt14 symbols
src/formatters/pattern.ts11 symbols
android/src/main/jni/TransformerTextInputJni.cpp9 symbols
src/registry.ts7 symbols
example/src/App.tsx7 symbols
scripts/generate-phone-data.ts6 symbols
android/src/main/java/com/appandflow/transformertextinput/TransformerTextInputDecoratorViewManager.kt6 symbols
src/formatters/currency.ts4 symbols
src/Transformer.ts4 symbols
android/src/main/java/com/appandflow/transformertextinput/TransformerTextInputPackage.kt4 symbols
src/TransformerTextInput.web.tsx3 symbols

For agents

$ claude mcp add react-native-transformer-text-input \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page