in vnext/Microsoft.ReactNative/Views/TextInputViewManager.cpp [472:694]
void TextInputShadowNode::updateProperties(winrt::Microsoft::ReactNative::JSValueObject &props) {
m_updating = true;
auto control = GetView().as<xaml::Controls::Control>();
auto textBox = control.try_as<xaml::Controls::TextBox>();
auto passwordBox = control.try_as<xaml::Controls::PasswordBox>();
auto hasKeyDownEvents = false;
auto markDirty = false;
for (auto &pair : props) {
const std::string &propertyName = pair.first;
const auto &propertyValue = pair.second;
// Applicable properties for both TextBox and PasswordBox
if (TryUpdateFontProperties(control, propertyName, propertyValue)) {
markDirty = true;
continue;
} else if (TryUpdateCharacterSpacing(control, propertyName, propertyValue)) {
markDirty = true;
continue;
} else if (propertyName == "allowFontScaling") {
markDirty = true;
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean)
control.IsTextScaleFactorEnabled(propertyValue.AsBoolean());
else if (propertyValue.IsNull())
control.ClearValue(xaml::Controls::Control::IsTextScaleFactorEnabledProperty());
} else if (propertyName == "clearTextOnFocus") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean)
m_shouldClearTextOnFocus = propertyValue.AsBoolean();
} else if (propertyName == "selectTextOnFocus") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean)
m_shouldSelectTextOnFocus = propertyValue.AsBoolean();
} else if (propertyName == "mostRecentEventCount") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Double ||
propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Int64) {
m_mostRecentEventCount = propertyValue.AsInt32();
}
} else if (propertyName == "contextMenuHidden") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean)
m_contextMenuHidden = propertyValue.AsBoolean();
} else if (propertyName == "caretHidden") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean) {
m_hideCaret = propertyValue.AsBoolean();
HideCaretIfNeeded();
}
} else if (propertyName == "secureTextEntry") {
markDirty = true;
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean) {
if (propertyValue.AsBoolean()) {
if (m_isTextBox) {
xaml::Controls::PasswordBox newPasswordBox;
ReparentView(newPasswordBox);
m_isTextBox = false;
registerEvents();
control = newPasswordBox.as<xaml::Controls::Control>();
passwordBox = newPasswordBox;
if (!m_placeholderTextColor.IsNull()) {
setPasswordBoxPlaceholderForeground(newPasswordBox, m_placeholderTextColor);
}
}
} else {
if (!m_isTextBox) {
xaml::Controls::TextBox newTextBox;
ReparentView(newTextBox);
m_isTextBox = true;
registerEvents();
control = newTextBox.as<xaml::Controls::Control>();
textBox = newTextBox;
if (!m_placeholderTextColor.IsNull()) {
textBox.PlaceholderForeground(SolidColorBrushFrom(m_placeholderTextColor));
}
}
}
}
} else if (propertyName == "maxLength") {
markDirty = true;
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Double ||
propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Int64) {
control.SetValue(
m_isTextBox ? xaml::Controls::TextBox::MaxLengthProperty()
: xaml::Controls::PasswordBox::MaxLengthProperty(),
winrt::PropertyValue::CreateInt32(propertyValue.AsInt32()));
} else if (propertyValue.IsNull()) {
control.ClearValue(
m_isTextBox ? xaml::Controls::TextBox::MaxLengthProperty()
: xaml::Controls::PasswordBox::MaxLengthProperty());
}
} else if (propertyName == "placeholder") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::String) {
control.SetValue(
m_isTextBox ? xaml::Controls::TextBox::PlaceholderTextProperty()
: xaml::Controls::PasswordBox::PlaceholderTextProperty(),
winrt::PropertyValue::CreateString(asHstring(propertyValue)));
} else if (propertyValue.IsNull()) {
control.ClearValue(
m_isTextBox ? xaml::Controls::TextBox::PlaceholderTextProperty()
: xaml::Controls::PasswordBox::PlaceholderTextProperty());
}
} else if (propertyName == "selectionColor") {
if (IsValidColorValue(propertyValue)) {
control.SetValue(
m_isTextBox ? xaml::Controls::TextBox::SelectionHighlightColorProperty()
: xaml::Controls::PasswordBox::SelectionHighlightColorProperty(),
SolidColorBrushFrom(propertyValue));
} else if (propertyValue.IsNull())
control.ClearValue(
m_isTextBox ? xaml::Controls::TextBox::SelectionHighlightColorProperty()
: xaml::Controls::PasswordBox::SelectionHighlightColorProperty());
} else if (propertyName == "keyboardType") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::String) {
auto inputScopeNameVaue = parseKeyboardType(propertyValue, m_isTextBox);
auto scope = xaml::Input::InputScope();
auto scopeName = xaml::Input::InputScopeName(inputScopeNameVaue);
auto names = scope.Names();
names.Append(scopeName);
control.SetValue(
m_isTextBox ? xaml::Controls::TextBox::InputScopeProperty()
: xaml::Controls::PasswordBox::InputScopeProperty(),
scope);
} else if (propertyValue.IsNull())
control.ClearValue(
m_isTextBox ? xaml::Controls::TextBox::InputScopeProperty()
: xaml::Controls::PasswordBox::InputScopeProperty());
} else if (propertyName == "placeholderTextColor") {
m_placeholderTextColor = nullptr;
if (textBox.try_as<xaml::Controls::ITextBox6>() && m_isTextBox) {
if (IsValidColorValue(propertyValue)) {
m_placeholderTextColor = propertyValue.Copy();
textBox.PlaceholderForeground(SolidColorBrushFrom(propertyValue));
} else if (propertyValue.IsNull())
textBox.ClearValue(xaml::Controls::TextBox::PlaceholderForegroundProperty());
} else if (m_isTextBox != true && IsValidColorValue(propertyValue)) {
setPasswordBoxPlaceholderForeground(passwordBox, propertyValue);
}
} else if (propertyName == "clearTextOnSubmit") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean)
m_shouldClearTextOnSubmit = propertyValue.AsBoolean();
} else if (propertyName == "submitKeyEvents") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Array)
m_submitKeyEvents = KeyboardHelper::FromJS(propertyValue);
else if (propertyValue.IsNull())
m_submitKeyEvents.clear();
} else if (propertyName == "keyDownEvents") {
hasKeyDownEvents = propertyValue.ItemCount() > 0;
} else if (propertyName == "autoFocus") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean)
m_autoFocus = propertyValue.AsBoolean();
} else if (propertyName == "editable") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean) {
m_isTextBox ? textBox.IsReadOnly(!propertyValue.AsBoolean()) : passwordBox.IsEnabled(propertyValue.AsBoolean());
} else if (propertyValue.IsNull()) {
m_isTextBox ? textBox.ClearValue(xaml::Controls::TextBox::IsReadOnlyProperty())
: passwordBox.ClearValue(xaml::Controls::Control::IsEnabledProperty());
}
} else {
if (m_isTextBox) { // Applicable properties for TextBox
if (TryUpdateTextAlignment(textBox, propertyName, propertyValue)) {
continue;
} else if (propertyName == "multiline") {
markDirty = true;
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean) {
const bool isMultiline = propertyValue.AsBoolean();
textBox.TextWrapping(isMultiline ? xaml::TextWrapping::Wrap : xaml::TextWrapping::NoWrap);
textBox.AcceptsReturn(isMultiline);
} else if (propertyValue.IsNull())
textBox.ClearValue(xaml::Controls::TextBox::TextWrappingProperty());
} else if (propertyName == "scrollEnabled") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean &&
textBox.TextWrapping() == xaml::TextWrapping::Wrap) {
auto scrollMode =
propertyValue.AsBoolean() ? xaml::Controls::ScrollMode::Auto : xaml::Controls::ScrollMode::Disabled;
xaml::Controls::ScrollViewer::SetVerticalScrollMode(textBox, scrollMode);
xaml::Controls::ScrollViewer::SetHorizontalScrollMode(textBox, scrollMode);
}
} else if (propertyName == "selection") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Object) {
auto selection = json_type_traits<Selection>::parseJson(propertyValue);
SetSelection(selection.start, selection.end);
}
} else if (propertyName == "spellCheck") {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean)
textBox.IsSpellCheckEnabled(propertyValue.AsBoolean());
else if (propertyValue.IsNull())
textBox.ClearValue(xaml::Controls::TextBox::IsSpellCheckEnabledProperty());
} else if (propertyName == "text") {
markDirty = true;
SetText(propertyValue);
} else if (propertyName == "autoCapitalize") {
if (textBox.try_as<xaml::Controls::ITextBox6>()) {
if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::String) {
if (propertyValue.AsString() == "characters") {
textBox.CharacterCasing(xaml::Controls::CharacterCasing::Upper);
} else { // anything else turns off autoCap (should be "None" but
// we don't support "words"/"senetences" yet)
textBox.CharacterCasing(xaml::Controls::CharacterCasing::Normal);
}
} else if (propertyValue.IsNull())
textBox.ClearValue(xaml::Controls::TextBox::CharacterCasingProperty());
}
}
} else { // Applicable properties for PasswordBox
if (propertyName == "text" && !m_isTextBox) {
markDirty = true;
SetText(propertyValue);
}
}
}
}
if (markDirty) {
GetViewManager()->MarkDirty(m_tag);
}
Super::updateProperties(props);
// We need to re-register the PreviewKeyDown handler so it is invoked after the ShadowNodeBase handler
if (hasKeyDownEvents) {
m_controlPreviewKeyDownRevoker.revoke();
registerPreviewKeyDown();
}
m_updating = false;
m_initialUpdateComplete = true;
}