Skip to content

Commit

Permalink
Merge pull request #24199 from margelo/fix/22204-task-desc-stays-on-top
Browse files Browse the repository at this point in the history
fix(#22204): Toggle label correctly
  • Loading branch information
Hayata Suenaga authored Sep 30, 2023
2 parents 52f0e3c + 052f23d commit 7c86d09
Showing 1 changed file with 24 additions and 25 deletions.
49 changes: 24 additions & 25 deletions src/components/TextInput/BaseTextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import useNativeDriver from '../../libs/useNativeDriver';
import * as Browser from '../../libs/Browser';

function BaseTextInput(props) {
const inputValue = props.value || props.defaultValue || '';
const initialActiveLabel = props.forceActiveLabel || inputValue.length > 0 || Boolean(props.prefixCharacter);
const initialValue = props.value || props.defaultValue || '';
const initialActiveLabel = props.forceActiveLabel || initialValue.length > 0 || Boolean(props.prefixCharacter);

const [isFocused, setIsFocused] = useState(false);
const [passwordHidden, setPasswordHidden] = useState(props.secureTextEntry);
Expand Down Expand Up @@ -145,30 +145,16 @@ function BaseTextInput(props) {
[props.autoGrowHeight, props.multiline],
);

useEffect(() => {
// Handle side effects when the value gets changed programatically from the outside

// In some cases, When the value prop is empty, it is not properly updated on the TextInput due to its uncontrolled nature, thus manually clearing the TextInput.
if (inputValue === '') {
input.current.clear();
}

if (inputValue) {
activateLabel();
}
}, [activateLabel, inputValue]);

// We capture whether the input has a value or not in a ref.
// It gets updated when the text gets changed.
const hasValueRef = useRef(inputValue.length > 0);
// The ref is needed when the component is uncontrolled and we don't have a value prop
const hasValueRef = useRef(initialValue.length > 0);
const inputValue = props.value || '';
const hasValue = inputValue.length > 0 || hasValueRef.current;

// Activate or deactivate the label when the focus changes:
// Activate or deactivate the label when either focus changes, or for controlled
// components when the value prop changes:
useEffect(() => {
// We can't use inputValue here directly, as it might contain
// the defaultValue, which doesn't get updated when the text changes.
// We can't use props.value either, as it might be undefined.
if (
hasValueRef.current ||
hasValue ||
isFocused ||
// If the text has been supplied by Chrome autofill, the value state is not synced with the value
// as Chrome doesn't trigger a change event. When there is autofill text, keep the label activated.
Expand All @@ -178,7 +164,16 @@ function BaseTextInput(props) {
} else {
deactivateLabel();
}
}, [activateLabel, deactivateLabel, inputValue, isFocused]);
}, [activateLabel, deactivateLabel, hasValue, isFocused]);

// When the value prop gets cleared externally, we need to keep the ref in sync:
useEffect(() => {
// Return early when component uncontrolled, or we still have a value
if (props.value === undefined || !_.isEmpty(props.value)) {
return;
}
hasValueRef.current = false;
}, [props.value]);

/**
* Set Value & activateLabel
Expand All @@ -192,9 +187,13 @@ function BaseTextInput(props) {
}

Str.result(props.onChangeText, value);

if (value && value.length > 0) {
hasValueRef.current = true;
activateLabel();
// When the componment is uncontrolled, we need to manually activate the label:
if (props.value === undefined) {
activateLabel();
}
} else {
hasValueRef.current = false;
}
Expand Down

0 comments on commit 7c86d09

Please sign in to comment.