1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#import <ABI47_0_0React/ABI47_0_0RCTBaseTextInputViewManager.h>
9
10#import <ABI47_0_0React/ABI47_0_0RCTBridge.h>
11#import <ABI47_0_0React/ABI47_0_0RCTConvert.h>
12#import <ABI47_0_0React/ABI47_0_0RCTFont.h>
13#import <ABI47_0_0React/ABI47_0_0RCTShadowView+Layout.h>
14#import <ABI47_0_0React/ABI47_0_0RCTShadowView.h>
15#import <ABI47_0_0React/ABI47_0_0RCTUIManager.h>
16#import <ABI47_0_0React/ABI47_0_0RCTUIManagerUtils.h>
17#import <ABI47_0_0React/ABI47_0_0RCTUIManagerObserverCoordinator.h>
18
19#import <ABI47_0_0React/ABI47_0_0RCTBaseTextInputShadowView.h>
20#import <ABI47_0_0React/ABI47_0_0RCTBaseTextInputView.h>
21#import <ABI47_0_0React/ABI47_0_0RCTConvert+Text.h>
22
23@interface ABI47_0_0RCTBaseTextInputViewManager () <ABI47_0_0RCTUIManagerObserver>
24
25@end
26
27@implementation ABI47_0_0RCTBaseTextInputViewManager
28{
29  NSHashTable<ABI47_0_0RCTBaseTextInputShadowView *> *_shadowViews;
30}
31
32ABI47_0_0RCT_EXPORT_MODULE()
33
34#pragma mark - Unified <TextInput> properties
35
36ABI47_0_0RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType)
37ABI47_0_0RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType)
38ABI47_0_0RCT_REMAP_VIEW_PROPERTY(contextMenuHidden, backedTextInputView.contextMenuHidden, BOOL)
39ABI47_0_0RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL)
40ABI47_0_0RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL)
41ABI47_0_0RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance)
42ABI47_0_0RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString)
43ABI47_0_0RCT_REMAP_VIEW_PROPERTY(placeholderTextColor, backedTextInputView.placeholderColor, UIColor)
44ABI47_0_0RCT_REMAP_VIEW_PROPERTY(returnKeyType, backedTextInputView.returnKeyType, UIReturnKeyType)
45ABI47_0_0RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, UIColor)
46ABI47_0_0RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType)
47ABI47_0_0RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL)
48ABI47_0_0RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode)
49ABI47_0_0RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL)
50ABI47_0_0RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL)
51ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL)
52ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
53ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
54ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType)
55ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(showSoftInputOnFocus, BOOL)
56ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
57ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
58ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(selection, ABI47_0_0RCTTextSelection)
59ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewID, NSString)
60ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(textContentType, NSString)
61ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(passwordRules, NSString)
62
63ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(onChange, ABI47_0_0RCTBubblingEventBlock)
64ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(onKeyPressSync, ABI47_0_0RCTDirectEventBlock)
65ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(onChangeSync, ABI47_0_0RCTDirectEventBlock)
66ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, ABI47_0_0RCTDirectEventBlock)
67ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(onTextInput, ABI47_0_0RCTDirectEventBlock)
68ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(onScroll, ABI47_0_0RCTDirectEventBlock)
69
70ABI47_0_0RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger)
71
72ABI47_0_0RCT_EXPORT_SHADOW_PROPERTY(text, NSString)
73ABI47_0_0RCT_EXPORT_SHADOW_PROPERTY(placeholder, NSString)
74ABI47_0_0RCT_EXPORT_SHADOW_PROPERTY(onContentSizeChange, ABI47_0_0RCTBubblingEventBlock)
75
76ABI47_0_0RCT_CUSTOM_VIEW_PROPERTY(multiline, BOOL, UIView)
77{
78  // No op.
79  // This View Manager doesn't use this prop but it must be exposed here via ViewConfig to enable Fabric component use it.
80}
81
82- (ABI47_0_0RCTShadowView *)shadowView
83{
84  ABI47_0_0RCTBaseTextInputShadowView *shadowView = [[ABI47_0_0RCTBaseTextInputShadowView alloc] initWithBridge:self.bridge];
85  shadowView.textAttributes.fontSizeMultiplier = [[[self.bridge
86                                                    moduleForName:@"AccessibilityManager"
87                                                    lazilyLoadIfNecessary:YES] valueForKey:@"multiplier"] floatValue];
88  [_shadowViews addObject:shadowView];
89  return shadowView;
90}
91
92- (void)setBridge:(ABI47_0_0RCTBridge *)bridge
93{
94  [super setBridge:bridge];
95
96  _shadowViews = [NSHashTable weakObjectsHashTable];
97
98  [bridge.uiManager.observerCoordinator addObserver:self];
99
100  [[NSNotificationCenter defaultCenter] addObserver:self
101                                           selector:@selector(handleDidUpdateMultiplierNotification)
102                                               name:@"ABI47_0_0RCTAccessibilityManagerDidUpdateMultiplierNotification"
103                                             object:[bridge moduleForName:@"AccessibilityManager"
104                                                    lazilyLoadIfNecessary:YES]];
105}
106
107ABI47_0_0RCT_EXPORT_METHOD(focus : (nonnull NSNumber *)viewTag)
108{
109  [self.bridge.uiManager addUIBlock:^(ABI47_0_0RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
110    UIView *view = viewRegistry[viewTag];
111    [view ABI47_0_0ReactFocus];
112  }];
113}
114
115ABI47_0_0RCT_EXPORT_METHOD(blur : (nonnull NSNumber *)viewTag)
116{
117  [self.bridge.uiManager addUIBlock:^(ABI47_0_0RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
118    UIView *view = viewRegistry[viewTag];
119    [view ABI47_0_0ReactBlur];
120  }];
121}
122
123ABI47_0_0RCT_EXPORT_METHOD(setTextAndSelection : (nonnull NSNumber *)viewTag
124                 mostRecentEventCount : (NSInteger)mostRecentEventCount
125                                value : (NSString *)value
126                                start : (NSInteger)start
127                                  end : (NSInteger)end)
128{
129  [self.bridge.uiManager addUIBlock:^(ABI47_0_0RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
130    ABI47_0_0RCTBaseTextInputView *view = (ABI47_0_0RCTBaseTextInputView *)viewRegistry[viewTag];
131    NSInteger eventLag = view.nativeEventCount - mostRecentEventCount;
132    if (eventLag != 0) {
133      return;
134    }
135    ABI47_0_0RCTExecuteOnUIManagerQueue(^{
136      ABI47_0_0RCTBaseTextInputShadowView *shadowView = (ABI47_0_0RCTBaseTextInputShadowView *)[self.bridge.uiManager shadowViewForABI47_0_0ReactTag:viewTag];
137      if (value) {
138        [shadowView setText:value];
139      }
140      [self.bridge.uiManager setNeedsLayout];
141      ABI47_0_0RCTExecuteOnMainQueue(^{
142        [view setSelectionStart:start selectionEnd:end];
143      });
144    });
145  }];
146}
147
148#pragma mark - ABI47_0_0RCTUIManagerObserver
149
150- (void)uiManagerWillPerformMounting:(__unused ABI47_0_0RCTUIManager *)uiManager
151{
152  for (ABI47_0_0RCTBaseTextInputShadowView *shadowView in _shadowViews) {
153    [shadowView uiManagerWillPerformMounting];
154  }
155}
156
157#pragma mark - Font Size Multiplier
158
159- (void)handleDidUpdateMultiplierNotification
160{
161  CGFloat fontSizeMultiplier = [[[self.bridge moduleForName:@"AccessibilityManager"]
162                                 valueForKey:@"multiplier"] floatValue];
163
164  NSHashTable<ABI47_0_0RCTBaseTextInputShadowView *> *shadowViews = _shadowViews;
165  ABI47_0_0RCTExecuteOnUIManagerQueue(^{
166    for (ABI47_0_0RCTBaseTextInputShadowView *shadowView in shadowViews) {
167      shadowView.textAttributes.fontSizeMultiplier = fontSizeMultiplier;
168      [shadowView dirtyLayout];
169    }
170
171    [self.bridge.uiManager setNeedsLayout];
172  });
173}
174
175@end
176