@expensify/react-native-live-markdown 0.1.254 → 0.1.256

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 (34) 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/MarkdownTextInputDecoratorComponentView.mm +6 -36
  10. package/apple/MarkdownTextInputDecoratorShadowNode.h +67 -0
  11. package/apple/MarkdownTextInputDecoratorShadowNode.mm +271 -0
  12. package/apple/RCTMarkdownUtils.mm +6 -0
  13. package/apple/RCTTextInputComponentView+Markdown.mm +0 -16
  14. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorState.h +3 -16
  15. package/lib/commonjs/MarkdownTextInput.js +7 -9
  16. package/lib/commonjs/MarkdownTextInput.js.map +1 -1
  17. package/lib/module/MarkdownTextInput.js +7 -9
  18. package/lib/module/MarkdownTextInput.js.map +1 -1
  19. package/lib/typescript/src/MarkdownTextInput.d.ts.map +1 -1
  20. package/package.json +3 -3
  21. package/src/MarkdownTextInput.tsx +8 -11
  22. package/android/src/main/java/com/expensify/livemarkdown/NativeProxy.java +0 -24
  23. package/android/src/main/new_arch/MarkdownCommitHook.cpp +0 -192
  24. package/android/src/main/new_arch/MarkdownCommitHook.h +0 -58
  25. package/android/src/main/new_arch/NativeProxy.cpp +0 -40
  26. package/android/src/main/new_arch/NativeProxy.h +0 -39
  27. package/android/src/main/new_arch/OnLoad.cpp +0 -8
  28. package/apple/MarkdownCommitHook.h +0 -46
  29. package/apple/MarkdownCommitHook.mm +0 -303
  30. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownShadowFamilyRegistry.cpp +0 -60
  31. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownShadowFamilyRegistry.h +0 -38
  32. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.cpp +0 -33
  33. package/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h +0 -46
  34. package/cpp/react/renderer/components/RNLiveMarkdownSpec/OwningShadowNodeFragment.h +0 -28
@@ -1,192 +0,0 @@
1
- #include <react/fabric/Binding.h>
2
- #include <react/jni/ReadableNativeMap.h>
3
- #include <react/renderer/core/ComponentDescriptor.h>
4
- #include <react/renderer/scheduler/Scheduler.h>
5
-
6
- #include "MarkdownCommitHook.h"
7
- #include "react/renderer/components/RNLiveMarkdownSpec/MarkdownShadowFamilyRegistry.h"
8
-
9
- using namespace facebook;
10
- using namespace react;
11
-
12
- namespace expensify {
13
- namespace livemarkdown {
14
-
15
- MarkdownCommitHook::MarkdownCommitHook(
16
- jni::global_ref<facebook::react::JFabricUIManager::javaobject>
17
- fabricUIManager)
18
- : fabricUIManager_(fabricUIManager),
19
- uiManager_(
20
- fabricUIManager->getBinding()->getScheduler()->getUIManager()) {
21
- uiManager_->registerCommitHook(*this);
22
- }
23
-
24
- MarkdownCommitHook::~MarkdownCommitHook() noexcept {
25
- uiManager_->unregisterCommitHook(*this);
26
- }
27
-
28
- RootShadowNode::Unshared MarkdownCommitHook::shadowTreeWillCommit(
29
- ShadowTree const &, RootShadowNode::Shared const &,
30
- RootShadowNode::Unshared const &newRootShadowNode) noexcept {
31
- auto rootNode = newRootShadowNode->ShadowNode::clone(ShadowNodeFragment{});
32
-
33
- // A preface to why we do the weird thing below:
34
- // On the new architecture there are two ways of measuring text on Android: by
35
- // passing a cache key, or by passing a measured text with attributes by a map
36
- // buffer. We could implement both, but that would increase the complexity of
37
- // the code and duplication between here and RN core, so we implement
38
- // measurement for map buffers since it's the independent one, and force RN to
39
- // use this path every time. It shouldn't have a negative performance impact,
40
- // since there is a cpp cache layer anyway.
41
- //
42
- // AndroidTextInputShadowNode is closed pretty tightly, but there's a one
43
- // place where we can insert ourselves (well, there are two but we really
44
- // shouldn't mess with vtable). The path to measurement looks like this:
45
- // AndroidTextInputShadowNode::measureContent ->
46
- // TextLayoutManager::measureAndroidComponentMapBuffer
47
- // -> (jni) -> FabricUIManager::measureMapBuffer ->
48
- // MountingManager::measureMapBuffer
49
- // We cannot modify the shadow node directly, but we can replace its
50
- // TextLayoutManager. Literally every method it has is linked statically so we
51
- // cannot override anything, but we can replace its ContextContainer where a
52
- // jni reference to the FabricUIManager is stored. Now `measureMapBuffer` is
53
- // private in the ui manager, but the only thing it does is calling
54
- // `measureMapBuffer` on MountingManager where it's public. At this point the
55
- // path forward is clear: we make a custom MountingManager that will perform
56
- // our measurement, then create a custom FabricUIManager which will direct
57
- // measurement to our MountingManager. Then we only need to create the
58
- // ContextContainer with our FabricUIManager, create the TextLayoutManager
59
- // with the newly created ContextContainer and replace the pointer to
60
- // TextLayoutManager inside the AndroidTextInputShadowNode.
61
-
62
- // In order to properly apply markdown formatting to the text input, we need
63
- // to update the TextInputShadowNode's state to reset the cache key and update
64
- // its TextLayoutManager reference, but we only have access to the
65
- // ShadowNodeFamilies of the decorator components. We also know that a
66
- // markdown decorator is always preceded with the TextInput to decorate, so we
67
- // need to take the sibling.
68
- std::vector<MarkdownTextInputDecoratorPair> nodesToUpdate;
69
- MarkdownShadowFamilyRegistry::runForEveryFamily([&rootNode, &nodesToUpdate](
70
- ShadowNodeFamily::Shared
71
- family) {
72
- // get the path from the root to the node from the decorator family
73
- const auto ancestors = family->getAncestors(*rootNode);
74
-
75
- if (!ancestors.empty()) {
76
- auto &parentNode = ancestors.back().first.get();
77
- auto index = ancestors.back().second;
78
-
79
- // this is node represented by one of the registered families and since we
80
- // only register markdown decorator shadow families, static casting should
81
- // be safe here
82
- const auto &decoratorNode =
83
- std::static_pointer_cast<const MarkdownTextInputDecoratorShadowNode>(
84
- parentNode.getChildren().at(index));
85
- // text input always precedes the decorator component
86
- const auto &previousSibling = parentNode.getChildren().at(index - 1);
87
-
88
- if (const auto &textInputNode =
89
- std::dynamic_pointer_cast<const AndroidTextInputShadowNode>(
90
- previousSibling)) {
91
- // store the pair of text input and decorator to update in the next step
92
- // we need both, decorator to get markdown style and text input to
93
- // update it
94
- nodesToUpdate.push_back({
95
- textInputNode,
96
- decoratorNode,
97
- });
98
- }
99
- }
100
- });
101
-
102
- for (const auto &nodes : nodesToUpdate) {
103
- const auto &textInputState =
104
- *std::static_pointer_cast<const ConcreteState<AndroidTextInputState>>(
105
- nodes.textInput->getState());
106
- const auto &stateData = textInputState.getData();
107
-
108
- rootNode = rootNode->cloneTree(
109
- nodes.textInput->getFamily(),
110
- [this, &stateData, &textInputState, &nodes](ShadowNode const &node) {
111
- std::shared_ptr<ShadowNode> newNode = nullptr;
112
-
113
- if (stateData.cachedAttributedStringId != 0) {
114
- auto newStateData =
115
- std::make_shared<AndroidTextInputState>(stateData);
116
-
117
- // force measurement of a map buffer
118
- newStateData->cachedAttributedStringId = 0;
119
-
120
- // setting -1 as the event counter makes sure that the update will be ignored by the java
121
- // part of the code, which is what we want as we don't change the attributed string here
122
- if (previousEventCount_.contains(nodes.textInput->getTag()) &&
123
- previousEventCount_[nodes.textInput->getTag()] == stateData.mostRecentEventCount) {
124
- newStateData->mostRecentEventCount = -1;
125
- } else {
126
- previousEventCount_[nodes.textInput->getTag()] = stateData.mostRecentEventCount;
127
- }
128
-
129
- auto newState = std::make_shared<const ConcreteState<AndroidTextInputState>>(
130
- newStateData, textInputState);
131
-
132
- newNode = node.clone({ .state = newState });
133
- } else {
134
- newNode = node.clone({});
135
- }
136
-
137
- const auto currentDecoratorProps =
138
- nodes.decorator->getProps()->rawProps["markdownStyle"];
139
- const auto currentParserId =
140
- nodes.decorator->getProps()->rawProps["parserId"].asInt();
141
- // if it's the first time we encounter this particular input or the
142
- // markdown styles have changed (in which case we need to reset the
143
- // cpp cache, to which we don't have a direct access), create a new
144
- // instance of TextLayoutManager that will be performing measurement
145
- // for this particular input
146
- if (!textLayoutManagers_.contains(nodes.textInput->getTag()) ||
147
- previousDecoratorProps_[nodes.textInput->getTag()] !=
148
- currentDecoratorProps ||
149
- previousParserId_[nodes.textInput->getTag()] != currentParserId) {
150
- static auto customUIManagerClass = jni::findClassStatic(
151
- "com/expensify/livemarkdown/CustomFabricUIManager");
152
- static auto createCustomUIManager =
153
- customUIManagerClass
154
- ->getStaticMethod<JFabricUIManager::javaobject(
155
- JFabricUIManager::javaobject, ReadableMap::javaobject, int)>(
156
- "create");
157
-
158
- auto const decoratorPropsRNM =
159
- ReadableNativeMap::newObjectCxxArgs(currentDecoratorProps);
160
- auto const decoratorPropsRM =
161
- jni::make_local(reinterpret_cast<ReadableMap::javaobject>(
162
- decoratorPropsRNM.get()));
163
-
164
- const auto customUIManager = jni::make_global(createCustomUIManager(
165
- customUIManagerClass, fabricUIManager_.get(),
166
- decoratorPropsRM.get(), currentParserId));
167
- const ContextContainer::Shared contextContainer =
168
- std::make_shared<ContextContainer const>();
169
- contextContainer->insert("FabricUIManager", customUIManager);
170
- textLayoutManagers_[nodes.textInput->getTag()] =
171
- std::make_shared<TextLayoutManager>(contextContainer);
172
- previousDecoratorProps_[nodes.textInput->getTag()] =
173
- currentDecoratorProps;
174
- previousParserId_[nodes.textInput->getTag()] = currentParserId;
175
- }
176
-
177
- // we need to replace the TextLayoutManager every time to make sure
178
- // the correct measurement code is run
179
- auto newTextInputShadowNode =
180
- std::static_pointer_cast<AndroidTextInputShadowNode>(newNode);
181
- newTextInputShadowNode->setTextLayoutManager(
182
- textLayoutManagers_[nodes.textInput->getTag()]);
183
-
184
- return newNode;
185
- });
186
- }
187
-
188
- return std::static_pointer_cast<RootShadowNode>(rootNode);
189
- }
190
-
191
- } // namespace livemarkdown
192
- } // namespace expensify
@@ -1,58 +0,0 @@
1
- #pragma once
2
-
3
- #include <fbjni/fbjni.h>
4
- #include <react/fabric/JFabricUIManager.h>
5
-
6
- #include <react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h>
7
- #include <react/renderer/uimanager/UIManager.h>
8
- #include <react/renderer/uimanager/UIManagerCommitHook.h>
9
-
10
- #include <memory>
11
- #include <unordered_map>
12
-
13
- #include "react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h"
14
-
15
- using namespace facebook;
16
- using namespace react;
17
-
18
- namespace expensify {
19
- namespace livemarkdown {
20
-
21
- struct MarkdownTextInputDecoratorPair {
22
- const std::shared_ptr<const AndroidTextInputShadowNode> textInput;
23
- const std::shared_ptr<const MarkdownTextInputDecoratorShadowNode> decorator;
24
- };
25
-
26
- class MarkdownCommitHook : public UIManagerCommitHook {
27
- public:
28
- MarkdownCommitHook(
29
- jni::global_ref<facebook::react::JFabricUIManager::javaobject>
30
- fabricUIManager);
31
-
32
- ~MarkdownCommitHook() noexcept override;
33
-
34
- void commitHookWasRegistered(UIManager const &) noexcept override {}
35
-
36
- void commitHookWasUnregistered(UIManager const &) noexcept override {}
37
-
38
- RootShadowNode::Unshared shadowTreeWillCommit(
39
- ShadowTree const &shadowTree,
40
- RootShadowNode::Shared const &oldRootShadowNode,
41
- RootShadowNode::Unshared const &newRootShadowNode) noexcept override;
42
-
43
- private:
44
- const jni::global_ref<facebook::react::JFabricUIManager::javaobject>
45
- fabricUIManager_;
46
- const std::shared_ptr<UIManager> uiManager_;
47
- std::unordered_map<facebook::react::Tag, SharedTextLayoutManager>
48
- textLayoutManagers_;
49
- std::unordered_map<facebook::react::Tag, folly::dynamic>
50
- previousDecoratorProps_;
51
- std::unordered_map<facebook::react::Tag, int>
52
- previousParserId_;
53
- std::unordered_map<facebook::react::Tag, int64_t>
54
- previousEventCount_;
55
- };
56
-
57
- } // namespace livemarkdown
58
- } // namespace expensify
@@ -1,40 +0,0 @@
1
- #include <fbjni/fbjni.h>
2
- #include <react/fabric/Binding.h>
3
- #include <react/renderer/scheduler/Scheduler.h>
4
-
5
- #include <string>
6
-
7
- #include "NativeProxy.h"
8
-
9
- namespace expensify {
10
- namespace livemarkdown {
11
-
12
- using namespace facebook;
13
- using namespace react;
14
-
15
- NativeProxy::NativeProxy(jni::alias_ref<NativeProxy::javaobject> jThis)
16
- : javaPart_(jni::make_global(jThis)) {}
17
-
18
- NativeProxy::~NativeProxy() {}
19
-
20
- void NativeProxy::registerNatives() {
21
- registerHybrid(
22
- {makeNativeMethod("initHybrid", NativeProxy::initHybrid),
23
- makeNativeMethod("createCommitHook", NativeProxy::createCommitHook)});
24
- }
25
-
26
- void NativeProxy::createCommitHook(
27
- jni::alias_ref<facebook::react::JFabricUIManager::javaobject>
28
- fabricUIManager) {
29
- const auto &globalUIManager = jni::make_global(fabricUIManager);
30
-
31
- this->commitHook_ = std::make_shared<MarkdownCommitHook>(globalUIManager);
32
- }
33
-
34
- jni::local_ref<NativeProxy::jhybriddata>
35
- NativeProxy::initHybrid(jni::alias_ref<jhybridobject> jThis) {
36
- return makeCxxInstance(jThis);
37
- }
38
-
39
- } // namespace livemarkdown
40
- } // namespace expensify
@@ -1,39 +0,0 @@
1
- #pragma once
2
-
3
- #include <fbjni/fbjni.h>
4
- #include <react/fabric/JFabricUIManager.h>
5
-
6
- #include <string>
7
-
8
- #include "MarkdownCommitHook.h"
9
-
10
- namespace expensify {
11
- namespace livemarkdown {
12
-
13
- using namespace facebook;
14
- using namespace facebook::jni;
15
-
16
- class NativeProxy : public jni::HybridClass<NativeProxy> {
17
- public:
18
- static auto constexpr kJavaDescriptor =
19
- "Lcom/expensify/livemarkdown/NativeProxy;";
20
- static jni::local_ref<jhybriddata>
21
- initHybrid(jni::alias_ref<jhybridobject> jThis);
22
- static void registerNatives();
23
-
24
- ~NativeProxy();
25
-
26
- private:
27
- friend HybridBase;
28
- jni::global_ref<NativeProxy::javaobject> javaPart_;
29
- std::shared_ptr<MarkdownCommitHook> commitHook_;
30
-
31
- explicit NativeProxy(jni::alias_ref<NativeProxy::javaobject> jThis);
32
-
33
- void
34
- createCommitHook(jni::alias_ref<facebook::react::JFabricUIManager::javaobject>
35
- fabricUIManager);
36
- };
37
-
38
- } // namespace livemarkdown
39
- } // namespace expensify
@@ -1,8 +0,0 @@
1
- #include <fbjni/fbjni.h>
2
-
3
- #include "NativeProxy.h"
4
-
5
- JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
6
- return facebook::jni::initialize(
7
- vm, [] { expensify::livemarkdown::NativeProxy::registerNatives(); });
8
- }
@@ -1,46 +0,0 @@
1
- #pragma once
2
-
3
- #include <react/renderer/components/iostextinput/TextInputShadowNode.h>
4
- #include <react/renderer/uimanager/UIManager.h>
5
- #include <react/renderer/uimanager/UIManagerCommitHook.h>
6
-
7
- #include <memory>
8
-
9
- #include "MarkdownTextInputDecoratorShadowNode.h"
10
- #include "RCTMarkdownUtils.h"
11
-
12
- using namespace facebook::react;
13
-
14
- namespace expensify {
15
- namespace livemarkdown {
16
-
17
- struct MarkdownTextInputDecoratorPair {
18
- const std::shared_ptr<const TextInputShadowNode> textInput;
19
- const std::shared_ptr<const MarkdownTextInputDecoratorShadowNode> decorator;
20
- };
21
-
22
- class MarkdownCommitHook : public UIManagerCommitHook {
23
- public:
24
- MarkdownCommitHook(const std::shared_ptr<UIManager> &uiManager);
25
-
26
- ~MarkdownCommitHook() noexcept override;
27
-
28
- void commitHookWasRegistered(UIManager const &) noexcept override {}
29
-
30
- void commitHookWasUnregistered(UIManager const &) noexcept override {}
31
-
32
- RootShadowNode::Unshared shadowTreeWillCommit(
33
- ShadowTree const &shadowTree,
34
- RootShadowNode::Shared const &oldRootShadowNode,
35
- RootShadowNode::Unshared const &newRootShadowNode) noexcept override;
36
-
37
- private:
38
- static RCTMarkdownUtils *
39
- getMarkdownUtils(const MarkdownTextInputDecoratorShadowNode &decorator);
40
- static RCTMarkdownUtils *getOrCreateMarkdownUtils(
41
- const MarkdownTextInputDecoratorShadowNode &decorator);
42
- const std::shared_ptr<UIManager> uiManager_;
43
- };
44
-
45
- } // namespace livemarkdown
46
- } // namespace expensify