Skip to content

Commit 4ac09ee

Browse files
authored
Merge pull request Expensify#65711 from Krishna2323/krishna2323/issue/65024
fix: Cursor is not shown in active magic code input.
2 parents f832fb5 + dadb7a9 commit 4ac09ee

2 files changed

Lines changed: 67 additions & 16 deletions

File tree

src/components/MagicCodeInput.tsx

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} fro
33
import type {NativeSyntheticEvent, TextInputFocusEventData, TextInputKeyPressEventData} from 'react-native';
44
import {StyleSheet, View} from 'react-native';
55
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
6+
import Animated, {useAnimatedStyle, useSharedValue, withDelay, withRepeat, withSequence, withTiming} from 'react-native-reanimated';
67
import useNetwork from '@hooks/useNetwork';
78
import useStyleUtils from '@hooks/useStyleUtils';
89
import useThemeStyles from '@hooks/useThemeStyles';
@@ -381,6 +382,17 @@ function MagicCodeInput(
381382
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
382383
}, [lastPressedDigit, isDisableKeyboard]);
383384

385+
const cursorOpacity = useSharedValue(1);
386+
387+
useEffect(() => {
388+
cursorOpacity.set(withRepeat(withSequence(withDelay(500, withTiming(0, {duration: 0})), withDelay(500, withTiming(1, {duration: 0}))), -1, false));
389+
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
390+
}, []);
391+
392+
const animatedCursorStyle = useAnimatedStyle(() => ({
393+
opacity: cursorOpacity.get(),
394+
}));
395+
384396
return (
385397
<>
386398
<View style={[styles.magicCodeInputContainer]}>
@@ -424,24 +436,40 @@ function MagicCodeInput(
424436
/>
425437
</View>
426438
</GestureDetector>
427-
{getInputPlaceholderSlots(maxLength).map((index) => (
428-
<View
429-
key={index}
430-
style={maxLength === CONST.MAGIC_CODE_LENGTH ? [styles.w15] : [styles.flex1, index !== 0 && styles.ml3]}
431-
>
439+
{getInputPlaceholderSlots(maxLength).map((index) => {
440+
const char = decomposeString(value, maxLength).at(index)?.trim() ?? '';
441+
const cursorMargin = char ? {marginLeft: 2} : {};
442+
const isFocused = focusedIndex === index;
443+
444+
return (
432445
<View
433-
style={[
434-
styles.textInputContainer,
435-
StyleUtils.getHeightOfMagicCodeInput(),
436-
hasError || errorText ? styles.borderColorDanger : {},
437-
focusedIndex === index ? styles.borderColorFocus : {},
438-
styles.pt0,
439-
]}
446+
key={index}
447+
style={maxLength === CONST.MAGIC_CODE_LENGTH ? [styles.w15] : [styles.flex1, index !== 0 && styles.ml3]}
440448
>
441-
<Text style={[styles.magicCodeInput, styles.textAlignCenter]}>{decomposeString(value, maxLength).at(index) ?? ''}</Text>
449+
<View
450+
style={[
451+
styles.textInputContainer,
452+
StyleUtils.getHeightOfMagicCodeInput(),
453+
hasError || errorText ? styles.borderColorDanger : {},
454+
focusedIndex === index ? styles.borderColorFocus : {},
455+
styles.pt0,
456+
{position: 'relative'},
457+
]}
458+
>
459+
<View style={styles.magicCodeInputValueContainer}>
460+
<Text style={[styles.magicCodeInput, styles.textAlignCenter]}>{char}</Text>
461+
{isFocused && !isDisableKeyboard && (
462+
<View style={[styles.magicCodeInputCursorContainer]}>
463+
{!!char && <Text style={[styles.magicCodeInput, styles.textAlignCenter, styles.opacity0]}>{char}</Text>}
464+
<Text style={[styles.magicCodeInput, {width: 1}]}> </Text>
465+
<Animated.Text style={[styles.magicCodeInputCursor, animatedCursorStyle, cursorMargin]}></Animated.Text>
466+
</View>
467+
)}
468+
</View>
469+
</View>
442470
</View>
443-
</View>
444-
))}
471+
);
472+
})}
445473
</View>
446474
{!!errorText && (
447475
<FormHelpMessage

src/styles/index.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3355,7 +3355,30 @@ const styles = (theme: ThemeColors) =>
33553355
magicCodeInput: {
33563356
fontSize: variables.fontSizeXLarge,
33573357
color: theme.heading,
3358-
lineHeight: variables.inputHeight,
3358+
lineHeight: variables.lineHeightXXXLarge,
3359+
},
3360+
3361+
magicCodeInputValueContainer: {
3362+
flex: 1,
3363+
justifyContent: 'center',
3364+
alignItems: 'center',
3365+
position: 'relative',
3366+
},
3367+
3368+
magicCodeInputCursorContainer: {
3369+
position: 'absolute',
3370+
textAlign: 'center',
3371+
flexDirection: 'row',
3372+
justifyContent: 'center',
3373+
overflow: 'visible',
3374+
width: '100%',
3375+
},
3376+
3377+
magicCodeInputCursor: {
3378+
fontSize: 24,
3379+
color: theme.heading,
3380+
fontFamily: FontUtils.fontFamily.platform.EXP_NEUE.fontFamily,
3381+
fontWeight: FontUtils.fontWeight.normal,
33593382
},
33603383

33613384
// Manually style transparent, in iOS Safari, an input in a container with its opacity set to

0 commit comments

Comments
 (0)