@expensify/react-native-live-markdown 0.1.255 → 0.1.257

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.
Files changed (35) hide show
  1. package/RNLiveMarkdown.podspec +2 -0
  2. package/android/src/main/java/com/expensify/livemarkdown/LiveMarkdownModule.java +0 -10
  3. package/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorView.java +5 -28
  4. package/android/src/main/java/com/expensify/livemarkdown/MarkdownTextInputDecoratorViewManagerSpec.java +3 -3
  5. package/android/src/main/new_arch/CMakeLists.txt +2 -1
  6. package/android/src/main/new_arch/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.cpp +135 -0
  7. package/android/src/main/new_arch/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h +75 -0
  8. package/apple/LiveMarkdownModule.mm +1 -53
  9. package/apple/MarkdownParser.mm +4 -4
  10. package/apple/MarkdownTextInputDecoratorComponentView.mm +6 -36
  11. package/apple/MarkdownTextInputDecoratorShadowNode.h +67 -0
  12. package/apple/MarkdownTextInputDecoratorShadowNode.mm +271 -0
  13. package/apple/RCTMarkdownUtils.mm +6 -0
  14. package/apple/RCTTextInputComponentView+Markdown.mm +0 -16
  15. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorState.h +3 -16
  16. package/lib/commonjs/MarkdownTextInput.js +7 -9
  17. package/lib/commonjs/MarkdownTextInput.js.map +1 -1
  18. package/lib/module/MarkdownTextInput.js +7 -9
  19. package/lib/module/MarkdownTextInput.js.map +1 -1
  20. package/lib/typescript/src/MarkdownTextInput.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/src/MarkdownTextInput.tsx +8 -11
  23. package/android/src/main/java/com/expensify/livemarkdown/NativeProxy.java +0 -24
  24. package/android/src/main/new_arch/MarkdownCommitHook.cpp +0 -192
  25. package/android/src/main/new_arch/MarkdownCommitHook.h +0 -58
  26. package/android/src/main/new_arch/NativeProxy.cpp +0 -40
  27. package/android/src/main/new_arch/NativeProxy.h +0 -39
  28. package/android/src/main/new_arch/OnLoad.cpp +0 -8
  29. package/apple/MarkdownCommitHook.h +0 -46
  30. package/apple/MarkdownCommitHook.mm +0 -303
  31. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownShadowFamilyRegistry.cpp +0 -60
  32. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownShadowFamilyRegistry.h +0 -38
  33. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.cpp +0 -33
  34. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h +0 -46
  35. package/cpp/react/renderer/components/RNLiveMarkdownSpec/OwningShadowNodeFragment.h +0 -28
@@ -34,6 +34,8 @@ Pod::Spec.new do |s|
34
34
  ].join(' '),
35
35
  }
36
36
 
37
+ s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/cpp\"" }
38
+
37
39
  install_modules_dependencies(s)
38
40
 
39
41
  if ENV['USE_FRAMEWORKS'] != nil
@@ -1,9 +1,6 @@
1
1
  package com.expensify.livemarkdown;
2
2
 
3
3
  import com.facebook.react.bridge.ReactApplicationContext;
4
- import com.facebook.react.fabric.FabricUIManager;
5
- import com.facebook.react.uimanager.UIManagerHelper;
6
- import com.facebook.react.uimanager.common.UIManagerType;
7
4
  import com.facebook.soloader.SoLoader;
8
5
 
9
6
  import java.util.Objects;
@@ -13,19 +10,12 @@ public class LiveMarkdownModule extends NativeLiveMarkdownModuleSpec {
13
10
  SoLoader.loadLibrary("livemarkdown");
14
11
  }
15
12
 
16
- private NativeProxy mNativeProxy;
17
13
  public LiveMarkdownModule(ReactApplicationContext reactContext) {
18
14
  super(reactContext);
19
-
20
- this.mNativeProxy = new NativeProxy();
21
15
  }
22
16
 
23
17
  @Override
24
18
  public boolean install() {
25
- FabricUIManager uiManager =
26
- (FabricUIManager) UIManagerHelper.getUIManager(getReactApplicationContext(), UIManagerType.FABRIC);
27
- mNativeProxy.createCommitHook(uiManager);
28
-
29
19
  long jsiRuntime = Objects.requireNonNull(getReactApplicationContext().getJavaScriptContextHolder(), "[react-native-live-markdown] JavaScriptContextHolder is null").get();
30
20
  injectJSIBindings(jsiRuntime);
31
21
 
@@ -1,34 +1,22 @@
1
1
  package com.expensify.livemarkdown;
2
2
 
3
- import androidx.annotation.Nullable;
4
-
5
3
  import android.content.Context;
6
4
  import android.text.Editable;
7
5
  import android.text.SpannableStringBuilder;
8
6
  import android.text.TextWatcher;
9
- import android.util.AttributeSet;
10
7
 
11
8
  import android.view.View;
12
- import android.view.ViewGroup;
13
- import android.view.ViewParent;
14
9
 
15
10
  import com.facebook.react.bridge.ReactContext;
16
11
  import com.facebook.react.views.textinput.ReactEditText;
12
+ import com.facebook.react.views.view.ReactViewGroup;
17
13
 
18
- public class MarkdownTextInputDecoratorView extends View {
14
+ public class MarkdownTextInputDecoratorView extends ReactViewGroup {
19
15
 
20
16
  public MarkdownTextInputDecoratorView(Context context) {
21
17
  super(context);
22
18
  }
23
19
 
24
- public MarkdownTextInputDecoratorView(Context context, @Nullable AttributeSet attrs) {
25
- super(context, attrs);
26
- }
27
-
28
- public MarkdownTextInputDecoratorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
29
- super(context, attrs, defStyleAttr);
30
- }
31
-
32
20
  private MarkdownStyle mMarkdownStyle;
33
21
 
34
22
  private int mParserId;
@@ -43,23 +31,12 @@ public class MarkdownTextInputDecoratorView extends View {
43
31
  protected void onAttachedToWindow() {
44
32
  super.onAttachedToWindow();
45
33
 
46
- View previousSibling = null;
47
- final ViewParent parent = this.getParent();
48
- if (parent instanceof ViewGroup) {
49
- final ViewGroup viewGroup = (ViewGroup) parent;
50
- for (int i = 1; i < viewGroup.getChildCount(); i++) {
51
- if (viewGroup.getChildAt(i) == this) {
52
- previousSibling = viewGroup.getChildAt(i - 1);
53
- break;
54
- }
55
- }
56
- }
57
-
58
- if (previousSibling instanceof ReactEditText) {
34
+ View child = getChildAt(0);
35
+ if (child instanceof ReactEditText) {
59
36
  mMarkdownUtils = new MarkdownUtils((ReactContext) getContext());
60
37
  mMarkdownUtils.setMarkdownStyle(mMarkdownStyle);
61
38
  mMarkdownUtils.setParserId(mParserId);
62
- mReactEditText = (ReactEditText) previousSibling;
39
+ mReactEditText = (ReactEditText) child;
63
40
  mTextWatcher = new MarkdownTextWatcher(mMarkdownUtils);
64
41
  mReactEditText.addTextChangedListener(mTextWatcher);
65
42
  applyNewStyles();
@@ -1,15 +1,15 @@
1
1
  package com.expensify.livemarkdown;
2
2
 
3
- import android.view.View;
3
+ import android.view.ViewGroup;
4
4
 
5
5
  import androidx.annotation.Nullable;
6
6
 
7
- import com.facebook.react.uimanager.SimpleViewManager;
7
+ import com.facebook.react.uimanager.ViewGroupManager;
8
8
  import com.facebook.react.uimanager.ViewManagerDelegate;
9
9
  import com.facebook.react.viewmanagers.MarkdownTextInputDecoratorViewManagerDelegate;
10
10
  import com.facebook.react.viewmanagers.MarkdownTextInputDecoratorViewManagerInterface;
11
11
 
12
- public abstract class MarkdownTextInputDecoratorViewManagerSpec<T extends View> extends SimpleViewManager<T> implements MarkdownTextInputDecoratorViewManagerInterface<T> {
12
+ public abstract class MarkdownTextInputDecoratorViewManagerSpec<T extends ViewGroup> extends ViewGroupManager<T> implements MarkdownTextInputDecoratorViewManagerInterface<T> {
13
13
  private final ViewManagerDelegate<T> mDelegate;
14
14
 
15
15
  public MarkdownTextInputDecoratorViewManagerSpec() {
@@ -11,7 +11,7 @@ set(LIB_CUSTOM_SOURCES_DIR ${LIB_CPP_DIR}/react/renderer/components/${LIB_LITERA
11
11
  set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni)
12
12
  set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL})
13
13
 
14
- file(GLOB LIB_MODULE_SRCS CONFIGURE_DEPENDS *.cpp)
14
+ file(GLOB LIB_MODULE_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNLiveMarkdownSpec/*.cpp)
15
15
  file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS ${LIB_CUSTOM_SOURCES_DIR}/*.cpp)
16
16
  file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp)
17
17
 
@@ -27,6 +27,7 @@ target_include_directories(
27
27
  ${LIB_TARGET_NAME}
28
28
  PUBLIC
29
29
  .
30
+ ./react/renderer/components/RNLiveMarkdownSpec
30
31
  ${LIB_ANDROID_GENERATED_JNI_DIR}
31
32
  ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}
32
33
  ${LIB_CPP_DIR}
@@ -0,0 +1,135 @@
1
+ #include "MarkdownTextInputDecoratorShadowNode.h"
2
+
3
+ #include <fbjni/fbjni.h>
4
+ #include <react/fabric/JFabricUIManager.h>
5
+ #include <react/jni/ReadableNativeMap.h>
6
+ #include <react/renderer/components/androidtextinput/AndroidTextInputState.h>
7
+ #include <react/renderer/components/view/conversions.h>
8
+ #include <react/renderer/core/ComponentDescriptor.h>
9
+ #include <yoga/Yoga.h>
10
+
11
+ namespace facebook {
12
+ namespace react {
13
+
14
+ extern const char MarkdownTextInputDecoratorViewComponentName[] =
15
+ "MarkdownTextInputDecoratorView";
16
+
17
+ void MarkdownTextInputDecoratorShadowNode::initialize() {
18
+ // Setting display: contents style results in ForceFlattenView trait being set
19
+ // on the shadow node. This trait causes the node not to have a host view. By
20
+ // removing the trait, it's possible to force RN to create a host view, layout
21
+ // of which can then be customized.
22
+ ShadowNode::traits_.unset(ShadowNodeTraits::ForceFlattenView);
23
+ }
24
+
25
+ void MarkdownTextInputDecoratorShadowNode::createCustomContextContainer() {
26
+ static const auto customFabricUIManagerClass = jni::findClassStatic(
27
+ "com/expensify/livemarkdown/CustomFabricUIManager");
28
+ static const auto createMethod =
29
+ customFabricUIManagerClass
30
+ ->getStaticMethod<JFabricUIManager::javaobject(
31
+ JFabricUIManager::javaobject, ReadableMap::javaobject, int)>(
32
+ "create");
33
+
34
+ const auto &rawProps = this->getProps()->rawProps;
35
+ const auto &markdownStyle = rawProps["markdownStyle"];
36
+ const auto parserId = rawProps["parserId"].asInt();
37
+
38
+ const auto decoratorPropsRNM =
39
+ ReadableNativeMap::newObjectCxxArgs(markdownStyle);
40
+ const auto decoratorPropsRM =
41
+ jni::make_local(reinterpret_cast<ReadableMap::javaobject>(
42
+ decoratorPropsRNM.get()));
43
+
44
+ const auto &fabricUIManager =
45
+ this->getContextContainer()->at<JFabricUIManager::javaobject>("FabricUIManager");
46
+
47
+ const auto customFabricUIManager = jni::make_global(createMethod(
48
+ customFabricUIManagerClass, fabricUIManager,
49
+ decoratorPropsRM.get(), parserId));
50
+ const auto contextContainer =
51
+ std::make_shared<ContextContainer const>();
52
+ contextContainer->insert("FabricUIManager", customFabricUIManager);
53
+
54
+ customContextContainer_ = contextContainer;
55
+ previousMarkdownStyle_ = markdownStyle;
56
+ previousParserId_ = parserId;
57
+ }
58
+
59
+ void MarkdownTextInputDecoratorShadowNode::updateCustomContextContainerIfNeeded() {
60
+ const auto markdownStyle =
61
+ this->getProps()->rawProps["markdownStyle"];
62
+ const auto parserId =
63
+ this->getProps()->rawProps["parserId"].asInt();
64
+
65
+ if (parserId != previousParserId_ || markdownStyle != previousMarkdownStyle_) {
66
+ createCustomContextContainer();
67
+ }
68
+ }
69
+
70
+ void MarkdownTextInputDecoratorShadowNode::overwriteTextLayoutManager() {
71
+ const auto &children = getChildren();
72
+ if (children.empty()) {
73
+ return;
74
+ }
75
+ react_native_assert(
76
+ children.size() == 1 &&
77
+ "MarkdownTextInputDecoratorView received more than one child");
78
+
79
+ const auto child = std::dynamic_pointer_cast<const AndroidTextInputShadowNode>(
80
+ children[0]);
81
+
82
+ react_native_assert(
83
+ child != nullptr &&
84
+ "MarkdownTextInputDecoratorView received child other than a TextInput");
85
+ child->ensureUnsealed();
86
+
87
+ const auto mutableChild = std::const_pointer_cast<AndroidTextInputShadowNode>(child);
88
+ mutableChild->setTextLayoutManager(
89
+ std::make_shared<TextLayoutManager>(customContextContainer_));
90
+ }
91
+
92
+ void MarkdownTextInputDecoratorShadowNode::appendChild(
93
+ const ShadowNode::Shared &child) {
94
+ YogaLayoutableShadowNode::appendChild(child);
95
+
96
+ overwriteTextLayoutManager();
97
+ }
98
+
99
+ void MarkdownTextInputDecoratorShadowNode::replaceChild(
100
+ const ShadowNode &oldChild, const ShadowNode::Shared &newChild,
101
+ size_t suggestedIndex) {
102
+ YogaLayoutableShadowNode::replaceChild(oldChild, newChild, suggestedIndex);
103
+
104
+ overwriteTextLayoutManager();
105
+ }
106
+
107
+ void MarkdownTextInputDecoratorShadowNode::layout(LayoutContext layoutContext) {
108
+ YogaLayoutableShadowNode::layout(layoutContext);
109
+
110
+ const auto &children = getChildren();
111
+ react_native_assert(
112
+ children.size() == 1 &&
113
+ "MarkdownTextInputDecoratorView didn't receive exactly one child");
114
+
115
+ auto child = std::static_pointer_cast<const YogaLayoutableShadowNode>(getChildren()[0]);
116
+ child->ensureUnsealed();
117
+ auto mutableChild = std::const_pointer_cast<YogaLayoutableShadowNode>(child);
118
+
119
+ // TODO: this may not be the correct way to do this
120
+ // Since nodes with display: contents are skipped during layout, they have
121
+ // zero-layout. To properly display the view, assign the layout metrics from
122
+ // the child (text input, which was calculated by Yoga) to the decorator view.
123
+ auto childMetrics = child->getLayoutMetrics();
124
+ setLayoutMetrics(childMetrics); // makes a copy
125
+
126
+ // Then, it's also needed to update the metrics on the child as the position
127
+ // is relative to the parent, which was just moved above. By zeroing the
128
+ // origin, the child is effectively moved to the same position it was before
129
+ // the manipulation here.
130
+ childMetrics.frame.origin = Point{};
131
+ mutableChild->setLayoutMetrics(childMetrics);
132
+ }
133
+
134
+ } // namespace react
135
+ } // namespace facebook
@@ -0,0 +1,75 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorState.h>
4
+ #include <react/renderer/components/RNLiveMarkdownSpec/EventEmitters.h>
5
+ #include <react/renderer/components/RNLiveMarkdownSpec/Props.h>
6
+ #include <react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h>
7
+
8
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
9
+ #include <react/renderer/core/LayoutContext.h>
10
+
11
+ namespace facebook {
12
+ namespace react {
13
+
14
+ JSI_EXPORT extern const char MarkdownTextInputDecoratorViewComponentName[];
15
+
16
+ class JSI_EXPORT MarkdownTextInputDecoratorShadowNode final
17
+ : public ConcreteViewShadowNode<MarkdownTextInputDecoratorViewComponentName,
18
+ MarkdownTextInputDecoratorViewProps,
19
+ MarkdownTextInputDecoratorViewEventEmitter,
20
+ MarkdownTextInputDecoratorState> {
21
+ public:
22
+ MarkdownTextInputDecoratorShadowNode(ShadowNodeFragment const &fragment,
23
+ ShadowNodeFamily::Shared const &family,
24
+ ShadowNodeTraits traits)
25
+ : ConcreteViewShadowNode(fragment, family, traits) {
26
+ initialize();
27
+ createCustomContextContainer();
28
+
29
+ if (fragment.children) {
30
+ overwriteTextLayoutManager();
31
+ }
32
+ }
33
+
34
+ MarkdownTextInputDecoratorShadowNode(ShadowNode const &sourceShadowNode,
35
+ ShadowNodeFragment const &fragment)
36
+ : ConcreteViewShadowNode(sourceShadowNode, fragment) {
37
+ initialize();
38
+
39
+ const auto &sourceDecorator = static_cast<const MarkdownTextInputDecoratorShadowNode &>(sourceShadowNode);
40
+
41
+ customContextContainer_ = sourceDecorator.customContextContainer_;
42
+ previousMarkdownStyle_ = sourceDecorator.previousMarkdownStyle_;
43
+ previousParserId_ = sourceDecorator.previousParserId_;
44
+
45
+ updateCustomContextContainerIfNeeded();
46
+
47
+ if (fragment.children) {
48
+ overwriteTextLayoutManager();
49
+ }
50
+ }
51
+
52
+ void appendChild(const ShadowNode::Shared &child) override;
53
+
54
+ void replaceChild(const ShadowNode &oldChild,
55
+ const ShadowNode::Shared &newChild,
56
+ size_t suggestedIndex = SIZE_MAX) override;
57
+
58
+ void layout(LayoutContext layoutContext) override;
59
+
60
+ private:
61
+ ContextContainer::Shared customContextContainer_;
62
+ folly::dynamic previousMarkdownStyle_;
63
+ int previousParserId_;
64
+
65
+ void initialize();
66
+
67
+ void overwriteTextLayoutManager();
68
+
69
+ void createCustomContextContainer();
70
+
71
+ void updateCustomContextContainerIfNeeded();
72
+ };
73
+
74
+ } // namespace react
75
+ } // namespace facebook
@@ -1,25 +1,13 @@
1
1
  #import "LiveMarkdownModule.h"
2
2
 
3
3
  #import <RNLiveMarkdown/RuntimeDecorator.h>
4
- #import <RNLiveMarkdown/MarkdownCommitHook.h>
5
-
6
4
  #import <React/RCTBridge+Private.h>
7
- #import <React/RCTScheduler.h>
8
- #import <React/RCTSurfacePresenter.h>
9
-
10
5
  #import <jsi/jsi.h>
11
6
 
12
7
  using namespace facebook;
13
8
  using namespace expensify::livemarkdown;
14
9
 
15
- // A turbomodule used to register the commit hook
16
- // I think this is the easiest way to access the UIManager, which we need to
17
- // actually register the hook
18
-
19
- @implementation LiveMarkdownModule {
20
- std::shared_ptr<MarkdownCommitHook> commitHook_;
21
- __weak RCTSurfacePresenter *surfacePresenter_;
22
- }
10
+ @implementation LiveMarkdownModule
23
11
 
24
12
  RCT_EXPORT_MODULE()
25
13
 
@@ -28,53 +16,13 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
28
16
  RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
29
17
  jsi::Runtime &rt = *(jsi::Runtime *)cxxBridge.runtime;
30
18
  expensify::livemarkdown::injectJSIBindings(rt);
31
-
32
- RCTScheduler *scheduler = [surfacePresenter_ scheduler];
33
- commitHook_ = std::make_shared<MarkdownCommitHook>(scheduler.uiManager);
34
-
35
19
  return @(1);
36
20
  }
37
21
 
38
- - (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
39
- {
40
- surfacePresenter_ = self.bridge.surfacePresenter;
41
- }
42
-
43
- - (void)setBridge:(RCTBridge *)bridge
44
- {
45
- [super setBridge:bridge];
46
-
47
- [[NSNotificationCenter defaultCenter] addObserver:self
48
- selector:@selector(handleJavaScriptDidLoadNotification:)
49
- name:RCTJavaScriptDidLoadNotification
50
- object:nil];
51
-
52
- // only within the first loading `self.bridge.surfacePresenter` exists
53
- // during the reload `self.bridge.surfacePresenter` is null
54
- if (self.bridge.surfacePresenter) {
55
- surfacePresenter_ = self.bridge.surfacePresenter;
56
- }
57
- }
58
-
59
- /*
60
- * Taken from RCTNativeAnimatedTurboModule:
61
- * This selector is invoked via BridgelessTurboModuleSetup.
62
- */
63
- - (void)setSurfacePresenter:(id<RCTSurfacePresenterStub>)surfacePresenter
64
- {
65
- surfacePresenter_ = surfacePresenter;
66
- }
67
-
68
22
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
69
23
  (const facebook::react::ObjCTurboModule::InitParams &)params {
70
24
  return std::make_shared<facebook::react::NativeLiveMarkdownModuleSpecJSI>(
71
25
  params);
72
26
  }
73
27
 
74
- - (void)invalidate {
75
- MarkdownShadowFamilyRegistry::reset();
76
- [[NSNotificationCenter defaultCenter] removeObserver:self];
77
- [super invalidate];
78
- }
79
-
80
28
  @end
@@ -23,7 +23,7 @@
23
23
  try {
24
24
  markdownWorklet = expensify::livemarkdown::getMarkdownWorklet([parserId intValue]);
25
25
  } catch (const std::out_of_range &error) {
26
- _prevText = text;
26
+ _prevText = [NSString stringWithString:text];
27
27
  _prevParserId = parserId;
28
28
  _prevMarkdownRanges = @[];
29
29
  return _prevMarkdownRanges;
@@ -36,7 +36,7 @@
36
36
  output = markdownRuntime->runGuarded(markdownWorklet, input);
37
37
  } catch (const jsi::JSError &error) {
38
38
  // Skip formatting, runGuarded will show the error in LogBox
39
- _prevText = text;
39
+ _prevText = [NSString stringWithString:text];
40
40
  _prevParserId = parserId;
41
41
  _prevMarkdownRanges = @[];
42
42
  return _prevMarkdownRanges;
@@ -62,13 +62,13 @@
62
62
  }
63
63
  } catch (const jsi::JSError &error) {
64
64
  RCTLogWarn(@"[react-native-live-markdown] Incorrect schema of worklet parser output: %s", error.getMessage().c_str());
65
- _prevText = text;
65
+ _prevText = [NSString stringWithString:text];
66
66
  _prevParserId = parserId;
67
67
  _prevMarkdownRanges = @[];
68
68
  return _prevMarkdownRanges;
69
69
  }
70
70
 
71
- _prevText = text;
71
+ _prevText = [NSString stringWithString:text];
72
72
  _prevParserId = parserId;
73
73
  _prevMarkdownRanges = markdownRanges;
74
74
  return _prevMarkdownRanges;
@@ -5,7 +5,6 @@
5
5
 
6
6
  #import <RNLiveMarkdown/MarkdownBackedTextInputDelegate.h>
7
7
  #import <RNLiveMarkdown/MarkdownLayoutManager.h>
8
- #import <RNLiveMarkdown/MarkdownShadowFamilyRegistry.h>
9
8
  #import <RNLiveMarkdown/MarkdownTextInputDecoratorComponentView.h>
10
9
  #import <RNLiveMarkdown/MarkdownTextInputDecoratorViewComponentDescriptor.h>
11
10
  #import <RNLiveMarkdown/RCTBackedTextFieldDelegateAdapter+Markdown.h>
@@ -26,7 +25,6 @@ using namespace facebook::react;
26
25
  __weak UIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
27
26
  __weak RCTBackedTextFieldDelegateAdapter *_adapter;
28
27
  __weak RCTUITextView *_textView;
29
- ShadowNodeFamily::Shared _decoratorFamily;
30
28
  }
31
29
 
32
30
  + (ComponentDescriptorProvider)componentDescriptorProvider
@@ -50,44 +48,13 @@ using namespace facebook::react;
50
48
  return self;
51
49
  }
52
50
 
53
- - (void)updateState:(const facebook::react::State::Shared &)state oldState:(const facebook::react::State::Shared &)oldState
51
+ - (void)didAddSubview:(UIView *)subview
54
52
  {
55
- auto data = std::static_pointer_cast<MarkdownTextInputDecoratorShadowNode::ConcreteState const>(state)->getData();
56
-
57
- if (_decoratorFamily != nullptr) {
58
- MarkdownShadowFamilyRegistry::unregisterFamilyForUpdates(_decoratorFamily);
59
- }
60
-
61
- _decoratorFamily = data.decoratorFamily;
62
- MarkdownShadowFamilyRegistry::registerFamilyForUpdates(_decoratorFamily);
63
- }
64
-
65
- - (void)willMoveToSuperview:(UIView *)newSuperview {
66
- if (newSuperview == nil) {
67
- MarkdownShadowFamilyRegistry::unregisterFamilyForUpdates(_decoratorFamily);
68
- _decoratorFamily = nullptr;
69
- }
70
-
71
- [super willMoveToSuperview:newSuperview];
72
- }
73
-
74
- - (void)didMoveToWindow {
75
- if (self.superview == nil) {
76
- return;
77
- }
78
-
79
- NSArray *viewsArray = self.superview.subviews;
80
- NSUInteger currentIndex = [viewsArray indexOfObject:self];
81
-
82
- react_native_assert(currentIndex != 0 && currentIndex != NSNotFound && "Error while finding current component.");
83
- UIView *view = [viewsArray objectAtIndex:currentIndex - 1];
84
-
85
- react_native_assert([view isKindOfClass:[RCTTextInputComponentView class]] && "Previous sibling component is not an instance of RCTTextInputComponentView.");
86
- _textInput = (RCTTextInputComponentView *)view;
53
+ react_native_assert([subview isKindOfClass:[RCTTextInputComponentView class]] && "Child component of MarkdownTextInputDecoratorComponentView is not an instance of RCTTextInputComponentView.");
54
+ _textInput = (RCTTextInputComponentView *)subview;
87
55
  _backedTextInputView = [_textInput valueForKey:@"_backedTextInputView"];
88
56
 
89
57
  _markdownUtils = [[RCTMarkdownUtils alloc] init];
90
- react_native_assert(_markdownStyle != nil);
91
58
  [_markdownUtils setMarkdownStyle:_markdownStyle];
92
59
  [_markdownUtils setParserId:_parserId];
93
60
 
@@ -121,6 +88,9 @@ using namespace facebook::react;
121
88
 
122
89
  - (void)willMoveToWindow:(UIWindow *)newWindow
123
90
  {
91
+ if (newWindow != nil) {
92
+ return;
93
+ }
124
94
  if (_textInput != nil) {
125
95
  [_textInput setMarkdownUtils:nil];
126
96
  }
@@ -0,0 +1,67 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorState.h>
4
+ #include <react/renderer/components/RNLiveMarkdownSpec/EventEmitters.h>
5
+ #include <react/renderer/components/RNLiveMarkdownSpec/Props.h>
6
+ #include <react/renderer/components/iostextinput/TextInputShadowNode.h>
7
+
8
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
9
+ #include <react/renderer/core/LayoutContext.h>
10
+
11
+ namespace facebook {
12
+ namespace react {
13
+
14
+ JSI_EXPORT extern const char MarkdownTextInputDecoratorViewComponentName[];
15
+
16
+ class JSI_EXPORT MarkdownTextInputDecoratorShadowNode final
17
+ : public ConcreteViewShadowNode<MarkdownTextInputDecoratorViewComponentName,
18
+ MarkdownTextInputDecoratorViewProps,
19
+ MarkdownTextInputDecoratorViewEventEmitter,
20
+ MarkdownTextInputDecoratorState> {
21
+ public:
22
+ MarkdownTextInputDecoratorShadowNode(ShadowNodeFragment const &fragment,
23
+ ShadowNodeFamily::Shared const &family,
24
+ ShadowNodeTraits traits)
25
+ : ConcreteViewShadowNode(fragment, family, traits) {
26
+ initialize();
27
+
28
+ if (fragment.children) {
29
+ overwriteMeasureCallbackConnector();
30
+ }
31
+ }
32
+
33
+ MarkdownTextInputDecoratorShadowNode(ShadowNode const &sourceShadowNode,
34
+ ShadowNodeFragment const &fragment)
35
+ : ConcreteViewShadowNode(sourceShadowNode, fragment) {
36
+ initialize();
37
+
38
+ if (fragment.children) {
39
+ overwriteMeasureCallbackConnector();
40
+ }
41
+ }
42
+
43
+ void appendChild(const ShadowNode::Shared &child) override;
44
+ void replaceChild(const ShadowNode &oldChild,
45
+ const ShadowNode::Shared &newChild,
46
+ size_t suggestedIndex = SIZE_MAX) override;
47
+ void layout(LayoutContext layoutContext) override;
48
+ Size
49
+ measureContent(const LayoutContext &layoutContext,
50
+ const LayoutConstraints &layoutConstraints) const override;
51
+
52
+ private:
53
+ void initialize();
54
+ void overwriteMeasureCallbackConnector();
55
+ void applyMarkdownFormattingToTextInputState(std::shared_ptr<TextInputShadowNode> node,
56
+ const LayoutContext &layoutContext) const;
57
+ static YGSize yogaNodeMeasureCallbackConnector(YGNodeConstRef yogaNode,
58
+ float width,
59
+ YGMeasureMode widthMode,
60
+ float height,
61
+ YGMeasureMode heightMode);
62
+ static YogaLayoutableShadowNode &
63
+ shadowNodeFromContext(YGNodeConstRef yogaNode);
64
+ };
65
+
66
+ } // namespace react
67
+ } // namespace facebook