mirror of
https://github.com/facebook/react-native.git
synced 2024-11-21 22:10:14 +00:00
feat(text-input): [iOS] inputAccessoryViewButtonLabel
prop (#47441)
Summary: Fixes https://github.com/facebook/react-native/issues/29244, also mentioned in https://github.com/facebook/react-native/issues/25009 As mentioned in the linked issues, the current return key label in the input accessory view is not localized. In the code, right now the texts are hardcoded (see: [RCTTextInputComponentView.mm](https://github.com/facebook/react-native/blob/main/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm#L552) and [RCTBaseTextInputView.mm](https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm#L694)). I could not find the historical reason for this, but doing some investigation there doesn't seem to be a way of getting the translated text into the code by using the existing props. (Ref: https://stackoverflow.com/a/58190342/5415299) The solution: adding a new property `inputAccessoryViewButtonLabel` which can be used to overwrite these defaults non-translated values. The property is optional to avoid breaking changes. The implementation works for both Fabric and Paper. ## Changelog: [IOS] [ADDED] - TextInput `inputAccessoryViewButtonLabel` prop Pull Request resolved: https://github.com/facebook/react-native/pull/47441 Test Plan: A new example has been added under the `TextInput` examples in the RNTester. See below: <details> <summary>Video demonstrating how the new prop behaves</summary> https://github.com/user-attachments/assets/b15cb8b8-494a-4f41-b434-e33eeef5d267 </details> Reviewed By: cipolleschi Differential Revision: D65533493 Pulled By: javache fbshipit-source-id: d80bf501ba3e38bf3b09833170780df45a26bb61
This commit is contained in:
parent
fc24171416
commit
32931466ed
@ -121,6 +121,7 @@ const RCTTextInputViewConfig = {
|
||||
},
|
||||
editable: true,
|
||||
inputAccessoryViewID: true,
|
||||
inputAccessoryViewButtonLabel: true,
|
||||
caretHidden: true,
|
||||
enablesReturnKeyAutomatically: true,
|
||||
placeholderTextColor: {
|
||||
|
@ -266,6 +266,12 @@ type IOSProps = $ReadOnly<{|
|
||||
*/
|
||||
inputAccessoryViewID?: ?string,
|
||||
|
||||
/**
|
||||
* An optional label that overrides the default input accessory view button label.
|
||||
* @platform ios
|
||||
*/
|
||||
inputAccessoryViewButtonLabel?: ?string,
|
||||
|
||||
/**
|
||||
* Determines the color of the keyboard.
|
||||
* @platform ios
|
||||
|
@ -310,6 +310,12 @@ type IOSProps = $ReadOnly<{|
|
||||
*/
|
||||
inputAccessoryViewID?: ?string,
|
||||
|
||||
/**
|
||||
* An optional label that overrides the default input accessory view button label.
|
||||
* @platform ios
|
||||
*/
|
||||
inputAccessoryViewButtonLabel?: ?string,
|
||||
|
||||
/**
|
||||
* Determines the color of the keyboard.
|
||||
* @platform ios
|
||||
|
@ -37,6 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, assign) BOOL caretHidden;
|
||||
|
||||
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;
|
||||
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewButtonLabel;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, assign) UITextFieldViewMode clearButtonMode;
|
||||
@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
|
||||
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;
|
||||
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewButtonLabel;
|
||||
@property (nonatomic, assign, readonly) CGFloat zoomScale;
|
||||
@property (nonatomic, assign, readonly) CGPoint contentOffset;
|
||||
@property (nonatomic, assign, readonly) UIEdgeInsets contentInset;
|
||||
|
@ -49,6 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, strong, nullable) NSNumber *maxLength;
|
||||
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;
|
||||
@property (nonatomic, copy) NSString *inputAccessoryViewID;
|
||||
@property (nonatomic, strong) NSString *inputAccessoryViewButtonLabel;
|
||||
@property (nonatomic, assign) UIKeyboardType keyboardType;
|
||||
@property (nonatomic, assign) BOOL showSoftInputOnFocus;
|
||||
|
||||
|
@ -384,6 +384,16 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)inputAccessoryViewButtonLabel
|
||||
{
|
||||
return self.backedTextInputView.inputAccessoryViewButtonLabel;
|
||||
}
|
||||
|
||||
- (void)setInputAccessoryViewButtonLabel:(NSString *)inputAccessoryViewButtonLabel
|
||||
{
|
||||
self.backedTextInputView.inputAccessoryViewButtonLabel = inputAccessoryViewButtonLabel;
|
||||
}
|
||||
|
||||
#pragma mark - RCTBackedTextInputDelegate
|
||||
|
||||
- (BOOL)textInputShouldBeginEditing
|
||||
@ -715,6 +725,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
|
||||
{
|
||||
UIView<RCTBackedTextInputViewProtocol> *textInputView = self.backedTextInputView;
|
||||
UIKeyboardType keyboardType = textInputView.keyboardType;
|
||||
NSString *inputAccessoryViewButtonLabel = textInputView.inputAccessoryViewButtonLabel;
|
||||
|
||||
// These keyboard types (all are number pads) don't have a Return Key button by default,
|
||||
// so we create an `inputAccessoryView` with this button for them.
|
||||
@ -722,11 +733,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
|
||||
UIReturnKeyType returnKeyType = textInputView.returnKeyType;
|
||||
|
||||
BOOL containsKeyType = [returnKeyTypesSet containsObject:@(returnKeyType)];
|
||||
BOOL containsInputAccessoryViewButtonLabel = inputAccessoryViewButtonLabel != nil;
|
||||
|
||||
BOOL shouldHaveInputAccessoryView =
|
||||
(keyboardType == UIKeyboardTypeNumberPad || keyboardType == UIKeyboardTypePhonePad ||
|
||||
keyboardType == UIKeyboardTypeDecimalPad || keyboardType == UIKeyboardTypeASCIICapableNumberPad) &&
|
||||
containsKeyType;
|
||||
(containsKeyType || containsInputAccessoryViewButtonLabel);
|
||||
|
||||
if (_hasInputAccessoryView == shouldHaveInputAccessoryView) {
|
||||
return;
|
||||
@ -735,7 +747,8 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
|
||||
_hasInputAccessoryView = shouldHaveInputAccessoryView;
|
||||
|
||||
if (shouldHaveInputAccessoryView) {
|
||||
NSString *buttonLabel = [self returnKeyTypeToString:returnKeyType];
|
||||
NSString *buttonLabel = inputAccessoryViewButtonLabel != nil ? inputAccessoryViewButtonLabel
|
||||
: [self returnKeyTypeToString:returnKeyType];
|
||||
|
||||
UIToolbar *toolbarView = [UIToolbar new];
|
||||
[toolbarView sizeToFit];
|
||||
|
@ -57,6 +57,7 @@ RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
|
||||
RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(selection, RCTTextSelection)
|
||||
RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewID, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewButtonLabel, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(textContentType, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(passwordRules, NSString)
|
||||
|
||||
|
@ -30,6 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, assign, getter=isEditable) BOOL editable;
|
||||
@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
|
||||
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;
|
||||
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewButtonLabel;
|
||||
@property (nonatomic, assign, readonly) CGFloat zoomScale;
|
||||
@property (nonatomic, assign, readonly) CGPoint contentOffset;
|
||||
@property (nonatomic, assign, readonly) UIEdgeInsets contentInset;
|
||||
|
@ -2962,6 +2962,7 @@ type IOSProps = $ReadOnly<{|
|
||||
| $ReadOnlyArray<DataDetectorTypesType>,
|
||||
enablesReturnKeyAutomatically?: ?boolean,
|
||||
inputAccessoryViewID?: ?string,
|
||||
inputAccessoryViewButtonLabel?: ?string,
|
||||
keyboardAppearance?: ?(\\"default\\" | \\"light\\" | \\"dark\\"),
|
||||
passwordRules?: ?PasswordRules,
|
||||
rejectResponderTermination?: ?boolean,
|
||||
@ -3314,6 +3315,7 @@ type IOSProps = $ReadOnly<{|
|
||||
| $ReadOnlyArray<DataDetectorTypesType>,
|
||||
enablesReturnKeyAutomatically?: ?boolean,
|
||||
inputAccessoryViewID?: ?string,
|
||||
inputAccessoryViewButtonLabel?: ?string,
|
||||
keyboardAppearance?: ?(\\"default\\" | \\"light\\" | \\"dark\\"),
|
||||
passwordRules?: ?PasswordRules,
|
||||
rejectResponderTermination?: ?boolean,
|
||||
|
@ -273,6 +273,11 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
||||
if (newTextInputProps.inputAccessoryViewID != oldTextInputProps.inputAccessoryViewID) {
|
||||
_backedTextInputView.inputAccessoryViewID = RCTNSStringFromString(newTextInputProps.inputAccessoryViewID);
|
||||
}
|
||||
|
||||
if (newTextInputProps.inputAccessoryViewButtonLabel != oldTextInputProps.inputAccessoryViewButtonLabel) {
|
||||
_backedTextInputView.inputAccessoryViewButtonLabel =
|
||||
RCTNSStringFromString(newTextInputProps.inputAccessoryViewButtonLabel);
|
||||
}
|
||||
[super updateProps:props oldProps:oldProps];
|
||||
|
||||
[self setDefaultInputAccessoryView];
|
||||
@ -581,22 +586,25 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
|
||||
|
||||
UIKeyboardType keyboardType = _backedTextInputView.keyboardType;
|
||||
UIReturnKeyType returnKeyType = _backedTextInputView.returnKeyType;
|
||||
NSString *inputAccessoryViewButtonLabel = _backedTextInputView.inputAccessoryViewButtonLabel;
|
||||
|
||||
BOOL containsKeyType = [returnKeyTypesSet containsObject:@(returnKeyType)];
|
||||
BOOL containsInputAccessoryViewButtonLabel = inputAccessoryViewButtonLabel != nil;
|
||||
|
||||
// These keyboard types (all are number pads) don't have a "returnKey" button by default,
|
||||
// so we create an `inputAccessoryView` with this button for them.
|
||||
BOOL shouldHaveInputAccessoryView =
|
||||
(keyboardType == UIKeyboardTypeNumberPad || keyboardType == UIKeyboardTypePhonePad ||
|
||||
keyboardType == UIKeyboardTypeDecimalPad || keyboardType == UIKeyboardTypeASCIICapableNumberPad) &&
|
||||
containsKeyType;
|
||||
(containsKeyType || containsInputAccessoryViewButtonLabel);
|
||||
|
||||
if ((_backedTextInputView.inputAccessoryView != nil) == shouldHaveInputAccessoryView) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldHaveInputAccessoryView) {
|
||||
NSString *buttonLabel = [self returnKeyTypeToString:returnKeyType];
|
||||
NSString *buttonLabel = inputAccessoryViewButtonLabel != nil ? inputAccessoryViewButtonLabel
|
||||
: [self returnKeyTypeToString:returnKeyType];
|
||||
|
||||
UIToolbar *toolbarView = [UIToolbar new];
|
||||
[toolbarView sizeToFit];
|
||||
|
@ -33,6 +33,12 @@ TextInputProps::TextInputProps(
|
||||
"inputAccessoryViewID",
|
||||
sourceProps.inputAccessoryViewID,
|
||||
{})),
|
||||
inputAccessoryViewButtonLabel(convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
"inputAccessoryViewButtonLabel",
|
||||
sourceProps.inputAccessoryViewButtonLabel,
|
||||
{})),
|
||||
onKeyPressSync(convertRawProp(
|
||||
context,
|
||||
rawProps,
|
||||
|
@ -37,6 +37,7 @@ class TextInputProps final : public BaseTextInputProps {
|
||||
std::optional<Selection> selection{};
|
||||
|
||||
const std::string inputAccessoryViewID{};
|
||||
const std::string inputAccessoryViewButtonLabel{};
|
||||
|
||||
bool onKeyPressSync{false};
|
||||
bool onChangeSync{false};
|
||||
|
@ -349,6 +349,27 @@ const textInputExamples: Array<RNTesterModuleExample> = [
|
||||
return <View>{examples}</View>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Custom Input Accessory View Button Label',
|
||||
render: function (): React.Node {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="Localized Label">
|
||||
<ExampleTextInput
|
||||
keyboardType="number-pad"
|
||||
inputAccessoryViewButtonLabel="Presiona aquí para terminar"
|
||||
/>
|
||||
</WithLabel>
|
||||
<WithLabel label="Custom Label">
|
||||
<ExampleTextInput
|
||||
keyboardType="ascii-capable-number-pad"
|
||||
inputAccessoryViewButtonLabel="Press here to finish"
|
||||
/>
|
||||
</WithLabel>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Nested content and `value` property',
|
||||
render: function (): React.Node {
|
||||
|
Loading…
Reference in New Issue
Block a user