@expensify/react-native-live-markdown 0.1.245 → 0.1.246

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,29 @@
1
+ #import <react/debug/react_native_assert.h>
1
2
  #import <react/renderer/components/RNLiveMarkdownSpec/Props.h>
3
+ #import <React/RCTFabricComponentsPlugins.h>
4
+ #import <React/RCTUITextField.h>
2
5
 
6
+ #import <RNLiveMarkdown/MarkdownLayoutManager.h>
7
+ #import <RNLiveMarkdown/MarkdownShadowFamilyRegistry.h>
3
8
  #import <RNLiveMarkdown/MarkdownTextInputDecoratorComponentView.h>
4
- #import <RNLiveMarkdown/MarkdownTextInputDecoratorView.h>
9
+ #import <RNLiveMarkdown/MarkdownTextInputDecoratorViewComponentDescriptor.h>
10
+ #import <RNLiveMarkdown/RCTBackedTextFieldDelegateAdapter+Markdown.h>
5
11
  #import <RNLiveMarkdown/RCTMarkdownStyle.h>
12
+ #import <RNLiveMarkdown/RCTTextInputComponentView+Markdown.h>
13
+ #import <RNLiveMarkdown/RCTUITextView+Markdown.h>
6
14
 
7
- #import <RNLiveMarkdown/MarkdownTextInputDecoratorViewComponentDescriptor.h>
8
- #import "MarkdownShadowFamilyRegistry.h"
9
- #import "RCTFabricComponentsPlugins.h"
15
+ #import <objc/runtime.h>
10
16
 
11
17
  using namespace facebook::react;
12
18
 
13
19
  @implementation MarkdownTextInputDecoratorComponentView {
14
- MarkdownTextInputDecoratorView *_view;
20
+ RCTMarkdownUtils *_markdownUtils;
21
+ RCTMarkdownStyle *_markdownStyle;
22
+ NSNumber *_parserId;
23
+ __weak RCTTextInputComponentView *_textInput;
24
+ __weak UIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
25
+ __weak RCTBackedTextFieldDelegateAdapter *_adapter;
26
+ __weak RCTUITextView *_textView;
15
27
  ShadowNodeFamily::Shared _decoratorFamily;
16
28
  }
17
29
 
@@ -31,10 +43,6 @@ using namespace facebook::react;
31
43
  if (self = [super initWithFrame:frame]) {
32
44
  static const auto defaultProps = std::make_shared<const MarkdownTextInputDecoratorViewProps>();
33
45
  _props = defaultProps;
34
-
35
- _view = [[MarkdownTextInputDecoratorView alloc] init];
36
-
37
- self.contentView = _view;
38
46
  }
39
47
 
40
48
  return self;
@@ -43,11 +51,11 @@ using namespace facebook::react;
43
51
  - (void)updateState:(const facebook::react::State::Shared &)state oldState:(const facebook::react::State::Shared &)oldState
44
52
  {
45
53
  auto data = std::static_pointer_cast<MarkdownTextInputDecoratorShadowNode::ConcreteState const>(state)->getData();
46
-
54
+
47
55
  if (_decoratorFamily != nullptr) {
48
56
  MarkdownShadowFamilyRegistry::unregisterFamilyForUpdates(_decoratorFamily);
49
57
  }
50
-
58
+
51
59
  _decoratorFamily = data.decoratorFamily;
52
60
  MarkdownShadowFamilyRegistry::registerFamilyForUpdates(_decoratorFamily);
53
61
  }
@@ -57,26 +65,116 @@ using namespace facebook::react;
57
65
  MarkdownShadowFamilyRegistry::unregisterFamilyForUpdates(_decoratorFamily);
58
66
  _decoratorFamily = nullptr;
59
67
  }
60
-
68
+
61
69
  [super willMoveToSuperview:newSuperview];
62
70
  }
63
71
 
72
+ - (void)didMoveToWindow {
73
+ if (self.superview == nil) {
74
+ return;
75
+ }
76
+
77
+ NSArray *viewsArray = self.superview.subviews;
78
+ NSUInteger currentIndex = [viewsArray indexOfObject:self];
79
+
80
+ react_native_assert(currentIndex != 0 && currentIndex != NSNotFound && "Error while finding current component.");
81
+ UIView *view = [viewsArray objectAtIndex:currentIndex - 1];
82
+
83
+ react_native_assert([view isKindOfClass:[RCTTextInputComponentView class]] && "Previous sibling component is not an instance of RCTTextInputComponentView.");
84
+ _textInput = (RCTTextInputComponentView *)view;
85
+ _backedTextInputView = [_textInput valueForKey:@"_backedTextInputView"];
86
+
87
+ _markdownUtils = [[RCTMarkdownUtils alloc] init];
88
+ react_native_assert(_markdownStyle != nil);
89
+ [_markdownUtils setMarkdownStyle:_markdownStyle];
90
+ [_markdownUtils setParserId:_parserId];
91
+
92
+ [_textInput setMarkdownUtils:_markdownUtils];
93
+ if ([_backedTextInputView isKindOfClass:[RCTUITextField class]]) {
94
+ RCTUITextField *textField = (RCTUITextField *)_backedTextInputView;
95
+ _adapter = [textField valueForKey:@"textInputDelegateAdapter"];
96
+ [_adapter setMarkdownUtils:_markdownUtils];
97
+ } else if ([_backedTextInputView isKindOfClass:[RCTUITextView class]]) {
98
+ _textView = (RCTUITextView *)_backedTextInputView;
99
+ [_textView setMarkdownUtils:_markdownUtils];
100
+ NSLayoutManager *layoutManager = _textView.layoutManager; // switching to TextKit 1 compatibility mode
101
+
102
+ // Correct content height in TextKit 1 compatibility mode. (See https://github.com/Expensify/App/issues/41567)
103
+ // Consider removing this fix if it is no longer needed after migrating to TextKit 2.
104
+ CGSize contentSize = _textView.contentSize;
105
+ CGRect textBounds = [layoutManager usedRectForTextContainer:_textView.textContainer];
106
+ contentSize.height = textBounds.size.height + _textView.textContainerInset.top + _textView.textContainerInset.bottom;
107
+ [_textView setContentSize:contentSize];
108
+
109
+ layoutManager.allowsNonContiguousLayout = NO; // workaround for onScroll issue
110
+ object_setClass(layoutManager, [MarkdownLayoutManager class]);
111
+ [layoutManager setValue:_markdownUtils forKey:@"markdownUtils"];
112
+ } else {
113
+ react_native_assert(false && "Cannot enable Markdown for this type of TextInput.");
114
+ }
115
+ }
116
+
117
+ - (void)willMoveToWindow:(UIWindow *)newWindow
118
+ {
119
+ if (_textInput != nil) {
120
+ [_textInput setMarkdownUtils:nil];
121
+ }
122
+ if (_adapter != nil) {
123
+ [_adapter setMarkdownUtils:nil];
124
+ }
125
+ if (_textView != nil) {
126
+ [_textView setMarkdownUtils:nil];
127
+ if (_textView.layoutManager != nil && [object_getClass(_textView.layoutManager) isEqual:[MarkdownLayoutManager class]]) {
128
+ [_textView.layoutManager setValue:nil forKey:@"markdownUtils"];
129
+ object_setClass(_textView.layoutManager, [NSLayoutManager class]);
130
+ }
131
+ }
132
+ }
133
+
64
134
  - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
65
135
  {
66
136
  const auto &oldViewProps = *std::static_pointer_cast<MarkdownTextInputDecoratorViewProps const>(_props);
67
137
  const auto &newViewProps = *std::static_pointer_cast<MarkdownTextInputDecoratorViewProps const>(props);
68
138
 
69
139
  if (oldViewProps.parserId != newViewProps.parserId) {
70
- [_view setParserId:@(newViewProps.parserId)];
140
+ [self setParserId:@(newViewProps.parserId)];
71
141
  }
72
142
 
73
143
  // TODO: if (oldViewProps.markdownStyle != newViewProps.markdownStyle)
74
144
  RCTMarkdownStyle *markdownStyle = [[RCTMarkdownStyle alloc] initWithStruct:newViewProps.markdownStyle];
75
- [_view setMarkdownStyle:markdownStyle];
145
+ [self setMarkdownStyle:markdownStyle];
76
146
 
77
147
  [super updateProps:props oldProps:oldProps];
78
148
  }
79
149
 
150
+ - (void)setMarkdownStyle:(RCTMarkdownStyle *)markdownStyle
151
+ {
152
+ // TODO: move to updateProps method
153
+ _markdownStyle = markdownStyle;
154
+ [_markdownUtils setMarkdownStyle:markdownStyle];
155
+ [self applyNewStyles];
156
+ }
157
+
158
+ - (void)setParserId:(NSNumber *)parserId
159
+ {
160
+ // TODO: move to updateProps method
161
+ _parserId = parserId;
162
+ [_markdownUtils setParserId:parserId];
163
+ [self applyNewStyles];
164
+ }
165
+
166
+ - (void)applyNewStyles
167
+ {
168
+ // TODO: call applyNewStyles only once if both markdownStyle and parserId change
169
+ if (_textView != nil) {
170
+ // We want to use `textStorage` for applying markdown when possible. Currently it's only available for UITextView
171
+ [_textView textDidChange];
172
+ } else {
173
+ // apply new styles
174
+ [_textInput _setAttributedString:_backedTextInputView.attributedText];
175
+ }
176
+ }
177
+
80
178
  Class<RCTComponentViewProtocol> MarkdownTextInputDecoratorViewCls(void)
81
179
  {
82
180
  return MarkdownTextInputDecoratorComponentView.class;
@@ -1,23 +1,11 @@
1
1
  #import <RNLiveMarkdown/MarkdownTextInputDecoratorViewManager.h>
2
- #import <RNLiveMarkdown/MarkdownTextInputDecoratorView.h>
3
2
 
4
3
  @implementation MarkdownTextInputDecoratorViewManager
5
4
 
6
5
  RCT_EXPORT_MODULE(MarkdownTextInputDecoratorView)
7
6
 
8
- - (UIView *)view
9
- {
10
- return [[MarkdownTextInputDecoratorView alloc] init];
11
- }
7
+ RCT_EXPORT_VIEW_PROPERTY(markdownStyle, NSDictionary)
12
8
 
13
- RCT_CUSTOM_VIEW_PROPERTY(markdownStyle, NSDictionary, MarkdownTextInputDecoratorView)
14
- {
15
- // implemented in MarkdownTextInputDecoratorView updateProps:
16
- }
17
-
18
- RCT_CUSTOM_VIEW_PROPERTY(parserId, NSNumber, MarkdownTextInputDecoratorView)
19
- {
20
- // implemented in MarkdownTextInputDecoratorView updateProps:
21
- }
9
+ RCT_EXPORT_VIEW_PROPERTY(parserId, NSNumber)
22
10
 
23
11
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expensify/react-native-live-markdown",
3
- "version": "0.1.245",
3
+ "version": "0.1.246",
4
4
  "description": "Drop-in replacement for React Native's TextInput component with Markdown formatting.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -1,14 +0,0 @@
1
- #import <UIKit/UIKit.h>
2
- #import <RNLiveMarkdown/RCTMarkdownStyle.h>
3
-
4
- NS_ASSUME_NONNULL_BEGIN
5
-
6
- @interface MarkdownTextInputDecoratorView : UIView
7
-
8
- - (void)setMarkdownStyle:(RCTMarkdownStyle *)markdownStyle;
9
-
10
- - (void)setParserId:(NSNumber *)parserId;
11
-
12
- @end
13
-
14
- NS_ASSUME_NONNULL_END
@@ -1,110 +0,0 @@
1
- #import <React/RCTUITextField.h>
2
- #import "react_native_assert.h"
3
-
4
- #import <RNLiveMarkdown/MarkdownLayoutManager.h>
5
- #import <RNLiveMarkdown/MarkdownTextInputDecoratorView.h>
6
- #import <RNLiveMarkdown/RCTBackedTextFieldDelegateAdapter+Markdown.h>
7
- #import <RNLiveMarkdown/RCTUITextView+Markdown.h>
8
-
9
- #import <RNLiveMarkdown/RCTTextInputComponentView+Markdown.h>
10
-
11
- #import <objc/runtime.h>
12
-
13
- @implementation MarkdownTextInputDecoratorView {
14
- RCTMarkdownUtils *_markdownUtils;
15
- RCTMarkdownStyle *_markdownStyle;
16
- NSNumber *_parserId;
17
- __weak RCTTextInputComponentView *_textInput;
18
- __weak UIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
19
- __weak RCTBackedTextFieldDelegateAdapter *_adapter;
20
- __weak RCTUITextView *_textView;
21
- }
22
-
23
- - (void)didMoveToWindow {
24
- if (self.superview.superview == nil) {
25
- return;
26
- }
27
-
28
- NSArray *viewsArray = self.superview.superview.subviews;
29
- NSUInteger currentIndex = [viewsArray indexOfObject:self.superview];
30
-
31
- react_native_assert(currentIndex != 0 && currentIndex != NSNotFound && "Error while finding current component.");
32
- UIView *view = [viewsArray objectAtIndex:currentIndex - 1];
33
-
34
- react_native_assert([view isKindOfClass:[RCTTextInputComponentView class]] && "Previous sibling component is not an instance of RCTTextInputComponentView.");
35
- _textInput = (RCTTextInputComponentView *)view;
36
- _backedTextInputView = [_textInput valueForKey:@"_backedTextInputView"];
37
-
38
- _markdownUtils = [[RCTMarkdownUtils alloc] init];
39
- react_native_assert(_markdownStyle != nil);
40
- [_markdownUtils setMarkdownStyle:_markdownStyle];
41
- [_markdownUtils setParserId:_parserId];
42
-
43
- [_textInput setMarkdownUtils:_markdownUtils];
44
- if ([_backedTextInputView isKindOfClass:[RCTUITextField class]]) {
45
- RCTUITextField *textField = (RCTUITextField *)_backedTextInputView;
46
- _adapter = [textField valueForKey:@"textInputDelegateAdapter"];
47
- [_adapter setMarkdownUtils:_markdownUtils];
48
- } else if ([_backedTextInputView isKindOfClass:[RCTUITextView class]]) {
49
- _textView = (RCTUITextView *)_backedTextInputView;
50
- [_textView setMarkdownUtils:_markdownUtils];
51
- NSLayoutManager *layoutManager = _textView.layoutManager; // switching to TextKit 1 compatibility mode
52
-
53
- // Correct content height in TextKit 1 compatibility mode. (See https://github.com/Expensify/App/issues/41567)
54
- // Consider removing this fix if it is no longer needed after migrating to TextKit 2.
55
- CGSize contentSize = _textView.contentSize;
56
- CGRect textBounds = [layoutManager usedRectForTextContainer:_textView.textContainer];
57
- contentSize.height = textBounds.size.height + _textView.textContainerInset.top + _textView.textContainerInset.bottom;
58
- [_textView setContentSize:contentSize];
59
-
60
- layoutManager.allowsNonContiguousLayout = NO; // workaround for onScroll issue
61
- object_setClass(layoutManager, [MarkdownLayoutManager class]);
62
- [layoutManager setValue:_markdownUtils forKey:@"markdownUtils"];
63
- } else {
64
- react_native_assert(false && "Cannot enable Markdown for this type of TextInput.");
65
- }
66
- }
67
-
68
- - (void)willMoveToWindow:(UIWindow *)newWindow
69
- {
70
- if (_textInput != nil) {
71
- [_textInput setMarkdownUtils:nil];
72
- }
73
- if (_adapter != nil) {
74
- [_adapter setMarkdownUtils:nil];
75
- }
76
- if (_textView != nil) {
77
- [_textView setMarkdownUtils:nil];
78
- if (_textView.layoutManager != nil && [object_getClass(_textView.layoutManager) isEqual:[MarkdownLayoutManager class]]) {
79
- [_textView.layoutManager setValue:nil forKey:@"markdownUtils"];
80
- object_setClass(_textView.layoutManager, [NSLayoutManager class]);
81
- }
82
- }
83
- }
84
-
85
- - (void)setMarkdownStyle:(RCTMarkdownStyle *)markdownStyle
86
- {
87
- _markdownStyle = markdownStyle;
88
- [_markdownUtils setMarkdownStyle:markdownStyle];
89
- [self applyNewStyles];
90
- }
91
-
92
- - (void)setParserId:(NSNumber *)parserId
93
- {
94
- _parserId = parserId;
95
- [_markdownUtils setParserId:parserId];
96
- [self applyNewStyles];
97
- }
98
-
99
- - (void)applyNewStyles
100
- {
101
- if (_textView != nil) {
102
- // We want to use `textStorage` for applying markdown when possible. Currently it's only available for UITextView
103
- [_textView textDidChange];
104
- } else {
105
- // apply new styles
106
- [_textInput _setAttributedString:_backedTextInputView.attributedText];
107
- }
108
- }
109
-
110
- @end