react-native-transformer-text-input 0.1.0-alpha.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -1
- package/android/src/main/java/com/appandflow/transformertextinput/TransformerTextInputDecoratorView.kt +30 -0
- package/cpp/TransformerTextInputDecoratorViewShadowNode.cpp +24 -1
- package/ios/TransformerTextInputDecoratorView.mm +42 -3
- package/lib/module/TransformerTextInput.js +24 -0
- package/lib/module/TransformerTextInput.js.map +1 -1
- package/lib/module/formatters/currency.js +122 -0
- package/lib/module/formatters/currency.js.map +1 -0
- package/lib/module/formatters/phone-data.js +4844 -0
- package/lib/module/formatters/phone-data.js.map +1 -0
- package/lib/module/formatters/phone-number.js +323 -61
- package/lib/module/formatters/phone-number.js.map +1 -1
- package/lib/module/registry.js +4 -3
- package/lib/module/registry.js.map +1 -1
- package/lib/typescript/scripts/generate-phone-data.d.ts +7 -0
- package/lib/typescript/scripts/generate-phone-data.d.ts.map +1 -0
- package/lib/typescript/src/TransformerTextInput.d.ts.map +1 -1
- package/lib/typescript/src/formatters/currency.d.ts +17 -0
- package/lib/typescript/src/formatters/currency.d.ts.map +1 -0
- package/lib/typescript/src/formatters/phone-data.d.ts +15 -0
- package/lib/typescript/src/formatters/phone-data.d.ts.map +1 -0
- package/lib/typescript/src/formatters/phone-number.d.ts +10 -4
- package/lib/typescript/src/formatters/phone-number.d.ts.map +1 -1
- package/lib/typescript/src/registry.d.ts.map +1 -1
- package/package.json +14 -1
- package/src/TransformerTextInput.tsx +23 -1
- package/src/formatters/currency.ts +142 -0
- package/src/formatters/phone-data.ts +5665 -0
- package/src/formatters/phone-number.ts +326 -68
- package/src/registry.ts +4 -3
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { Transformer, type Selection } from '../Transformer';
|
|
2
|
-
import {
|
|
2
|
+
import { COUNTRY_PHONE_DATA, type PhoneFormat } from './phone-data';
|
|
3
3
|
|
|
4
4
|
export type PhoneNumberTransformerOptions = {
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* Currently only 'US' is supported.
|
|
6
|
+
* ISO 3166-1 alpha-2 country code for phone number formatting.
|
|
8
7
|
* @default 'US'
|
|
9
8
|
*/
|
|
10
|
-
country?:
|
|
9
|
+
country?: string;
|
|
10
|
+
/**
|
|
11
|
+
* When false, the output only contains the formatted national number
|
|
12
|
+
* (without the "+{callingCode} " prefix). Useful when the calling code
|
|
13
|
+
* is displayed separately (e.g., in a flag button).
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
includeCallingCode?: boolean;
|
|
11
17
|
/**
|
|
12
18
|
* Enable debug logging for transformer operations.
|
|
13
19
|
* @default false
|
|
@@ -15,6 +21,12 @@ export type PhoneNumberTransformerOptions = {
|
|
|
15
21
|
debug?: boolean;
|
|
16
22
|
};
|
|
17
23
|
|
|
24
|
+
// Extract all digits from text
|
|
25
|
+
const extractDigits = (text: string): string => {
|
|
26
|
+
'worklet';
|
|
27
|
+
return text.replace(/\D/g, '');
|
|
28
|
+
};
|
|
29
|
+
|
|
18
30
|
// Count digits before a position in text
|
|
19
31
|
const countDigitsBefore = (text: string, pos: number): number => {
|
|
20
32
|
'worklet';
|
|
@@ -28,36 +40,237 @@ const countDigitsBefore = (text: string, pos: number): number => {
|
|
|
28
40
|
return count;
|
|
29
41
|
};
|
|
30
42
|
|
|
31
|
-
//
|
|
32
|
-
|
|
43
|
+
// Select the best format for a given national number based on leading digits.
|
|
44
|
+
// Iterates formats and tests the leadingDigits regex against the start of digits.
|
|
45
|
+
// Returns the first match, or the last format as fallback.
|
|
46
|
+
const selectFormat = (
|
|
47
|
+
nationalDigits: string,
|
|
48
|
+
formats: PhoneFormat[],
|
|
49
|
+
): PhoneFormat | null => {
|
|
33
50
|
'worklet';
|
|
34
|
-
|
|
51
|
+
if (formats.length === 0) return null;
|
|
52
|
+
if (nationalDigits.length === 0) return formats[formats.length - 1]!;
|
|
53
|
+
|
|
54
|
+
for (const format of formats) {
|
|
55
|
+
if (!format.leadingDigits) {
|
|
56
|
+
// No leading digits constraint — matches everything
|
|
57
|
+
return format;
|
|
58
|
+
}
|
|
59
|
+
// Test leading digits regex against the national digits.
|
|
60
|
+
// The regex should match from the start of the digits.
|
|
61
|
+
const re = new RegExp('^(?:' + format.leadingDigits + ')');
|
|
62
|
+
if (re.test(nationalDigits)) {
|
|
63
|
+
return format;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Fallback to last format
|
|
68
|
+
return formats[formats.length - 1]!;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Count the max digits the format pattern can consume by counting \d occurrences
|
|
72
|
+
// in the capture groups.
|
|
73
|
+
const getFormatMaxDigits = (pattern: string): number => {
|
|
74
|
+
'worklet';
|
|
75
|
+
let count = 0;
|
|
76
|
+
// Each \\d or \d in the pattern represents one digit slot.
|
|
77
|
+
// But patterns use quantifiers like {3} or {3,4} — we want the max.
|
|
78
|
+
// Simple approach: count the max digits by examining the pattern groups.
|
|
79
|
+
// Groups look like (\d{3}) or (\d{2,4}) or (\d{3,12})
|
|
80
|
+
// We'll parse {n} and {n,m} to get max values.
|
|
81
|
+
let i = 0;
|
|
82
|
+
while (i < pattern.length) {
|
|
83
|
+
if (
|
|
84
|
+
pattern[i] === '\\' &&
|
|
85
|
+
i + 1 < pattern.length &&
|
|
86
|
+
pattern[i + 1] === 'd'
|
|
87
|
+
) {
|
|
88
|
+
i += 2;
|
|
89
|
+
if (i < pattern.length && pattern[i] === '{') {
|
|
90
|
+
// Parse {n} or {n,m}
|
|
91
|
+
const closeBrace = pattern.indexOf('}', i);
|
|
92
|
+
if (closeBrace !== -1) {
|
|
93
|
+
const inner = pattern.slice(i + 1, closeBrace);
|
|
94
|
+
const commaIdx = inner.indexOf(',');
|
|
95
|
+
if (commaIdx !== -1) {
|
|
96
|
+
// {n,m} — use max
|
|
97
|
+
count += parseInt(inner.slice(commaIdx + 1), 10) || 0;
|
|
98
|
+
} else {
|
|
99
|
+
count += parseInt(inner, 10) || 0;
|
|
100
|
+
}
|
|
101
|
+
i = closeBrace + 1;
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// Just \d without quantifier — 1 digit
|
|
105
|
+
count += 1;
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
i++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return count;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Build a partial format for when we don't have enough digits to match the full pattern.
|
|
115
|
+
// We expand digit groups one at a time and fill what we can.
|
|
116
|
+
const buildPartialFormat = (digits: string, format: PhoneFormat): string => {
|
|
117
|
+
'worklet';
|
|
118
|
+
// Parse the pattern to extract groups
|
|
119
|
+
// Pattern like (\d{3})(\d{3})(\d{4}) with template ($1) $2-$3
|
|
120
|
+
// We need to figure out group sizes and fill them progressively
|
|
121
|
+
|
|
122
|
+
const groups: number[] = [];
|
|
123
|
+
let i = 0;
|
|
124
|
+
const pattern = format.pattern;
|
|
125
|
+
|
|
126
|
+
while (i < pattern.length) {
|
|
127
|
+
if (pattern[i] === '(' && i + 1 < pattern.length) {
|
|
128
|
+
// Find matching close paren
|
|
129
|
+
let depth = 1;
|
|
130
|
+
let j = i + 1;
|
|
131
|
+
while (j < pattern.length && depth > 0) {
|
|
132
|
+
if (pattern[j] === '(') depth++;
|
|
133
|
+
else if (pattern[j] === ')') depth--;
|
|
134
|
+
j++;
|
|
135
|
+
}
|
|
136
|
+
// Extract group content
|
|
137
|
+
const groupContent = pattern.slice(i + 1, j - 1);
|
|
138
|
+
// Count max digits in this group
|
|
139
|
+
const groupMax = getFormatMaxDigits(groupContent);
|
|
140
|
+
if (groupMax > 0) {
|
|
141
|
+
groups.push(groupMax);
|
|
142
|
+
}
|
|
143
|
+
i = j;
|
|
144
|
+
} else {
|
|
145
|
+
i++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (groups.length === 0) return digits;
|
|
150
|
+
|
|
151
|
+
// Build the result by walking the template and replacing placeholders.
|
|
152
|
+
// We track which groups got filled and which didn't.
|
|
153
|
+
let digitIdx = 0;
|
|
154
|
+
let result = '';
|
|
155
|
+
let lastGroupComplete = false;
|
|
156
|
+
let allGroupsFilled = true;
|
|
157
|
+
|
|
158
|
+
// Walk through the template character by character
|
|
159
|
+
let ti = 0;
|
|
160
|
+
while (ti < format.template.length) {
|
|
161
|
+
const tc = format.template[ti];
|
|
162
|
+
if (tc === '$' && ti + 1 < format.template.length) {
|
|
163
|
+
const groupNum = parseInt(format.template[ti + 1]!, 10);
|
|
164
|
+
if (!isNaN(groupNum) && groupNum >= 1 && groupNum <= groups.length) {
|
|
165
|
+
const groupSize = groups[groupNum - 1]!;
|
|
166
|
+
const available = digits.length - digitIdx;
|
|
167
|
+
if (available <= 0) {
|
|
168
|
+
allGroupsFilled = false;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
const chunk = digits.slice(digitIdx, digitIdx + groupSize);
|
|
172
|
+
digitIdx += chunk.length;
|
|
173
|
+
result += chunk;
|
|
174
|
+
lastGroupComplete = chunk.length === groupSize;
|
|
175
|
+
if (chunk.length < groupSize) {
|
|
176
|
+
allGroupsFilled = false;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
ti += 2;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Literal character — only include if we haven't run out of digits
|
|
184
|
+
result += tc;
|
|
185
|
+
ti++;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (allGroupsFilled) {
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Handle trailing: if last group was fully filled, keep trailing separators
|
|
193
|
+
// (like "555" → "(555) " with template "($1) $2-$3")
|
|
194
|
+
// If last group was NOT fully filled, strip trailing non-digit chars
|
|
195
|
+
if (lastGroupComplete) {
|
|
196
|
+
// Keep trailing separators up to the next placeholder
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Strip trailing non-digit chars for incomplete groups
|
|
201
|
+
return result.replace(/[^\d]+$/, '');
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// Apply a format to national digits. Returns the formatted national number.
|
|
205
|
+
const applyFormat = (nationalDigits: string, format: PhoneFormat): string => {
|
|
206
|
+
'worklet';
|
|
207
|
+
const re = new RegExp(format.pattern);
|
|
208
|
+
const maxDigits = getFormatMaxDigits(format.pattern);
|
|
209
|
+
const clamped = nationalDigits.slice(0, maxDigits);
|
|
210
|
+
|
|
211
|
+
// Only apply template if we have enough digits for at least the first group
|
|
212
|
+
const match = clamped.match(re);
|
|
213
|
+
if (match) {
|
|
214
|
+
return clamped.replace(re, format.template);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Partial input — build a partial format by expanding the pattern groups progressively.
|
|
218
|
+
return buildPartialFormat(clamped, format);
|
|
35
219
|
};
|
|
36
220
|
|
|
37
|
-
//
|
|
38
|
-
|
|
221
|
+
// Map cursor position from digit-space to formatted-space.
|
|
222
|
+
// Given a count of digits the cursor is after, find the position
|
|
223
|
+
// in the formatted string after that many digits.
|
|
224
|
+
const mapCursorToFormatted = (
|
|
225
|
+
formatted: string,
|
|
226
|
+
digitCount: number,
|
|
227
|
+
): number => {
|
|
39
228
|
'worklet';
|
|
40
|
-
|
|
229
|
+
if (digitCount <= 0) {
|
|
230
|
+
// Find position of first digit in formatted string
|
|
231
|
+
for (let i = 0; i < formatted.length; i++) {
|
|
232
|
+
const c = formatted[i];
|
|
233
|
+
if (c !== undefined && c >= '0' && c <= '9') {
|
|
234
|
+
return i;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
let count = 0;
|
|
241
|
+
for (let i = 0; i < formatted.length; i++) {
|
|
242
|
+
const c = formatted[i];
|
|
243
|
+
if (c !== undefined && c >= '0' && c <= '9') {
|
|
244
|
+
count++;
|
|
245
|
+
if (count === digitCount) {
|
|
246
|
+
return i + 1;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return formatted.length;
|
|
41
251
|
};
|
|
42
252
|
|
|
43
253
|
export class PhoneNumberTransformer extends Transformer {
|
|
44
254
|
constructor({
|
|
45
255
|
country = 'US',
|
|
256
|
+
includeCallingCode = true,
|
|
46
257
|
debug = false,
|
|
47
258
|
}: PhoneNumberTransformerOptions = {}) {
|
|
48
|
-
|
|
259
|
+
const countryData = COUNTRY_PHONE_DATA[country];
|
|
260
|
+
if (!countryData) {
|
|
49
261
|
throw new Error(
|
|
50
|
-
`[PhoneNumberTransformer] Country "${country}" is not supported
|
|
262
|
+
`[PhoneNumberTransformer] Country "${country}" is not supported.`,
|
|
51
263
|
);
|
|
52
264
|
}
|
|
53
265
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
266
|
+
const callingCode = countryData.callingCode;
|
|
267
|
+
const formats = countryData.formats;
|
|
268
|
+
const prefix = '+' + callingCode + ' ';
|
|
269
|
+
// Pre-compute these outside the worklet so only simple string/number
|
|
270
|
+
// values are captured in the closure (more reliable across worklet runtimes).
|
|
271
|
+
const outputPrefix = includeCallingCode ? prefix : '';
|
|
272
|
+
const outputPrefixLen = outputPrefix.length;
|
|
273
|
+
const codeToStrip = includeCallingCode ? callingCode : '';
|
|
61
274
|
|
|
62
275
|
const worklet = (input: {
|
|
63
276
|
value: string;
|
|
@@ -73,34 +286,56 @@ export class PhoneNumberTransformer extends Transformer {
|
|
|
73
286
|
const allDigits = extractDigits(value);
|
|
74
287
|
const prevAllDigits = extractDigits(previousValue);
|
|
75
288
|
|
|
76
|
-
|
|
77
|
-
|
|
289
|
+
// Handle completely empty
|
|
290
|
+
if (allDigits.length === 0) {
|
|
291
|
+
return { value: '', selection: { start: 0, end: 0 } };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let nationalDigits: string;
|
|
295
|
+
let prevNationalDigits: string;
|
|
296
|
+
let strippedCallingCode = false;
|
|
78
297
|
|
|
79
|
-
|
|
80
|
-
|
|
298
|
+
if (codeToStrip.length > 0) {
|
|
299
|
+
// Strip calling code from front to get national digits
|
|
300
|
+
if (allDigits.startsWith(codeToStrip)) {
|
|
301
|
+
nationalDigits = allDigits.slice(codeToStrip.length);
|
|
302
|
+
strippedCallingCode = true;
|
|
303
|
+
} else {
|
|
304
|
+
nationalDigits = allDigits;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (prevAllDigits.startsWith(codeToStrip)) {
|
|
308
|
+
prevNationalDigits = prevAllDigits.slice(codeToStrip.length);
|
|
309
|
+
} else {
|
|
310
|
+
prevNationalDigits = prevAllDigits;
|
|
311
|
+
}
|
|
81
312
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
313
|
+
// Special case: only calling code digits remain
|
|
314
|
+
if (nationalDigits.length === 0 && strippedCallingCode) {
|
|
315
|
+
if (value.length < previousValue.length) {
|
|
316
|
+
// Deleting — clear everything
|
|
317
|
+
return { value: '', selection: { start: 0, end: 0 } };
|
|
318
|
+
}
|
|
319
|
+
// Show prefix
|
|
320
|
+
return {
|
|
321
|
+
value: outputPrefix,
|
|
322
|
+
selection: { start: outputPrefixLen, end: outputPrefixLen },
|
|
323
|
+
};
|
|
87
324
|
}
|
|
88
|
-
|
|
89
|
-
|
|
325
|
+
} else {
|
|
326
|
+
// National-only mode: all digits are national, no calling code handling
|
|
327
|
+
nationalDigits = allDigits;
|
|
328
|
+
prevNationalDigits = prevAllDigits;
|
|
90
329
|
}
|
|
91
330
|
|
|
92
|
-
// Calculate digit positions for
|
|
331
|
+
// Calculate digit positions for cursor mapping
|
|
93
332
|
const digitsBeforeStart = countDigitsBefore(value, selection.start);
|
|
94
333
|
const digitsBeforeEnd = countDigitsBefore(value, selection.end);
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
: digitsBeforeEnd;
|
|
101
|
-
|
|
102
|
-
// Detect formatting char deletion at this level
|
|
103
|
-
// (PatternTransformer can't detect it because we pass only digits)
|
|
334
|
+
const callingCodeLen = strippedCallingCode ? codeToStrip.length : 0;
|
|
335
|
+
const adjustedStart = Math.max(0, digitsBeforeStart - callingCodeLen);
|
|
336
|
+
const adjustedEnd = Math.max(0, digitsBeforeEnd - callingCodeLen);
|
|
337
|
+
|
|
338
|
+
// Detect formatting char deletion
|
|
104
339
|
const isCaret = selection.start === selection.end;
|
|
105
340
|
const deletedFormattingChar =
|
|
106
341
|
isCaret &&
|
|
@@ -108,7 +343,6 @@ export class PhoneNumberTransformer extends Transformer {
|
|
|
108
343
|
nationalDigits.length === prevNationalDigits.length &&
|
|
109
344
|
nationalDigits.length > 0;
|
|
110
345
|
|
|
111
|
-
// If formatting char was deleted, remove the digit before cursor
|
|
112
346
|
let finalStart = adjustedStart;
|
|
113
347
|
let finalEnd = adjustedEnd;
|
|
114
348
|
if (deletedFormattingChar && adjustedStart > 0) {
|
|
@@ -119,33 +353,57 @@ export class PhoneNumberTransformer extends Transformer {
|
|
|
119
353
|
finalEnd = adjustedStart - 1;
|
|
120
354
|
}
|
|
121
355
|
|
|
122
|
-
//
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
:
|
|
147
|
-
|
|
148
|
-
|
|
356
|
+
// Select format based on leading digits
|
|
357
|
+
const format = selectFormat(nationalDigits, formats);
|
|
358
|
+
if (!format) {
|
|
359
|
+
// No format available — just show digits
|
|
360
|
+
const result = outputPrefix + nationalDigits;
|
|
361
|
+
const pos = outputPrefixLen + finalStart;
|
|
362
|
+
return { value: result, selection: { start: pos, end: pos } };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Apply the selected format
|
|
366
|
+
const formatted = applyFormat(nationalDigits, format);
|
|
367
|
+
const result = outputPrefix + formatted;
|
|
368
|
+
|
|
369
|
+
// Map cursor position
|
|
370
|
+
const cursorAtEnd = selection.end >= value.length;
|
|
371
|
+
const prevCursorAtEnd = previousSelection.end >= previousValue.length;
|
|
372
|
+
|
|
373
|
+
if (debug) {
|
|
374
|
+
console.log('[PhoneNumberTransformer]', {
|
|
375
|
+
input: { value, selection },
|
|
376
|
+
nationalDigits,
|
|
377
|
+
format: format.template,
|
|
378
|
+
formatted,
|
|
379
|
+
result,
|
|
380
|
+
cursor: {
|
|
381
|
+
finalStart,
|
|
382
|
+
finalEnd,
|
|
383
|
+
deletedFormattingChar,
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Cursor at end — put at end
|
|
389
|
+
if (isCaret && cursorAtEnd && prevCursorAtEnd) {
|
|
390
|
+
return {
|
|
391
|
+
value: result,
|
|
392
|
+
selection: { start: result.length, end: result.length },
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Map cursor through the formatted output
|
|
397
|
+
// We need to find where digit N is in the formatted result
|
|
398
|
+
const newStart =
|
|
399
|
+
outputPrefixLen + mapCursorToFormatted(formatted, finalStart);
|
|
400
|
+
const newEnd =
|
|
401
|
+
outputPrefixLen + mapCursorToFormatted(formatted, finalEnd);
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
value: result,
|
|
405
|
+
selection: { start: newStart, end: newEnd },
|
|
406
|
+
};
|
|
149
407
|
};
|
|
150
408
|
|
|
151
409
|
super(worklet);
|
package/src/registry.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runOnUI } from 'react-native-worklets';
|
|
1
|
+
import { runOnUI, executeOnUIRuntimeSync } from 'react-native-worklets';
|
|
2
2
|
import NativeTransformerTextInputModule from './NativeTransformerTextInputModule';
|
|
3
3
|
import { type Selection, type Transformer } from './Transformer';
|
|
4
4
|
import { computeUncontrolledSelection, validateSelection } from './selection';
|
|
@@ -29,8 +29,9 @@ function initializeIfNeeded() {
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
//
|
|
33
|
-
|
|
32
|
+
// Set up registry on UI runtime synchronously so it is guaranteed to exist
|
|
33
|
+
// when native code accesses it after install().
|
|
34
|
+
executeOnUIRuntimeSync(() => {
|
|
34
35
|
'worklet';
|
|
35
36
|
|
|
36
37
|
const transformersMap = new Map<number, TransformerWrapper>();
|