react-native-typerich 0.1.0

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 (74) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +37 -0
  3. package/TypeRichTextInput.podspec +20 -0
  4. package/android/build.gradle +99 -0
  5. package/android/generated/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TypeRichTextInputViewManagerDelegate.java +100 -0
  6. package/android/generated/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TypeRichTextInputViewManagerInterface.java +38 -0
  7. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.cpp +22 -0
  8. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.h +24 -0
  9. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.cpp +70 -0
  10. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.h +59 -0
  11. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/Props.cpp +132 -0
  12. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/Props.h +51 -0
  13. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.cpp +17 -0
  14. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.h +23 -0
  15. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/States.cpp +16 -0
  16. package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/States.h +20 -0
  17. package/android/gradle.properties +5 -0
  18. package/android/src/main/AndroidManifest.xml +2 -0
  19. package/android/src/main/AndroidManifestNew.xml +2 -0
  20. package/android/src/main/java/com/typerich/MeasurementStore.kt +148 -0
  21. package/android/src/main/java/com/typerich/TypeRichTextInputView.kt +503 -0
  22. package/android/src/main/java/com/typerich/TypeRichTextInputViewLayoutManager.kt +30 -0
  23. package/android/src/main/java/com/typerich/TypeRichTextInputViewManager.kt +188 -0
  24. package/android/src/main/java/com/typerich/TypeRichTextInputViewPackage.kt +19 -0
  25. package/android/src/main/java/com/typerich/events/OnChangeSelectionEvent.kt +29 -0
  26. package/android/src/main/java/com/typerich/events/OnChangeTextEvent.kt +35 -0
  27. package/android/src/main/java/com/typerich/events/OnInputBlurEvent.kt +27 -0
  28. package/android/src/main/java/com/typerich/events/OnInputFocusEvent.kt +27 -0
  29. package/android/src/main/java/com/typerich/events/OnPasteImageEvent.kt +45 -0
  30. package/android/src/main/new_arch/CMakeLists.txt +73 -0
  31. package/android/src/main/new_arch/TypeRichTextInputViewSpec.cpp +22 -0
  32. package/android/src/main/new_arch/TypeRichTextInputViewSpec.h +26 -0
  33. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewComponentDescriptor.h +36 -0
  34. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewMeasurementManager.cpp +83 -0
  35. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewMeasurementManager.h +25 -0
  36. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewShadowNode.cpp +132 -0
  37. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewShadowNode.h +54 -0
  38. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewState.cpp +9 -0
  39. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewState.h +28 -0
  40. package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/conversions.h +21 -0
  41. package/ios/TypeRichTextInputView.h +14 -0
  42. package/ios/TypeRichTextInputView.mm +71 -0
  43. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.cpp +22 -0
  44. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.h +24 -0
  45. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.cpp +70 -0
  46. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.h +59 -0
  47. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/Props.cpp +132 -0
  48. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/Props.h +51 -0
  49. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/RCTComponentViewHelpers.h +80 -0
  50. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.cpp +17 -0
  51. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.h +23 -0
  52. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/States.cpp +16 -0
  53. package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/States.h +20 -0
  54. package/lib/module/TypeRichTextInput.js +50 -0
  55. package/lib/module/TypeRichTextInput.js.map +1 -0
  56. package/lib/module/TypeRichTextInputNativeComponent.ts +92 -0
  57. package/lib/module/index.js +5 -0
  58. package/lib/module/index.js.map +1 -0
  59. package/lib/module/package.json +1 -0
  60. package/lib/module/types/react-native-codegen.d.js +2 -0
  61. package/lib/module/types/react-native-codegen.d.js.map +1 -0
  62. package/lib/typescript/package.json +1 -0
  63. package/lib/typescript/src/TypeRichTextInput.d.ts +35 -0
  64. package/lib/typescript/src/TypeRichTextInput.d.ts.map +1 -0
  65. package/lib/typescript/src/TypeRichTextInputNativeComponent.d.ts +57 -0
  66. package/lib/typescript/src/TypeRichTextInputNativeComponent.d.ts.map +1 -0
  67. package/lib/typescript/src/index.d.ts +4 -0
  68. package/lib/typescript/src/index.d.ts.map +1 -0
  69. package/package.json +180 -0
  70. package/react-native.config.js +13 -0
  71. package/src/TypeRichTextInput.tsx +115 -0
  72. package/src/TypeRichTextInputNativeComponent.ts +92 -0
  73. package/src/index.tsx +6 -0
  74. package/src/types/react-native-codegen.d.ts +11 -0
@@ -0,0 +1,19 @@
1
+ package com.typerich
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+ import java.util.ArrayList
8
+
9
+ class TypeRichTextInputViewPackage : ReactPackage {
10
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
11
+ val viewManagers: MutableList<ViewManager<*, *>> = ArrayList()
12
+ viewManagers.add(TypeRichTextInputViewManager())
13
+ return viewManagers
14
+ }
15
+
16
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
17
+ return emptyList()
18
+ }
19
+ }
@@ -0,0 +1,29 @@
1
+ package com.typerich.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ class OnChangeSelectionEvent(surfaceId: Int, viewId: Int, private val text: String, private val start: Int, private val end: Int, private val experimentalSynchronousEvents: Boolean) :
8
+ Event<OnChangeSelectionEvent>(surfaceId, viewId) {
9
+
10
+ override fun getEventName(): String {
11
+ return EVENT_NAME
12
+ }
13
+
14
+ override fun getEventData(): WritableMap {
15
+ val eventData: WritableMap = Arguments.createMap()
16
+ eventData.putString("text", text)
17
+ eventData.putInt("start", start)
18
+ eventData.putInt("end", end)
19
+ return eventData
20
+ }
21
+
22
+ override fun experimental_isSynchronous(): Boolean {
23
+ return experimentalSynchronousEvents
24
+ }
25
+
26
+ companion object {
27
+ const val EVENT_NAME: String = "onChangeSelection"
28
+ }
29
+ }
@@ -0,0 +1,35 @@
1
+ package com.typerich.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ class OnChangeTextEvent(
8
+ surfaceId: Int,
9
+ viewId: Int,
10
+ private val text: String,
11
+ private val experimentalSynchronousEvents: Boolean
12
+ ) : Event<OnChangeTextEvent>(surfaceId, viewId) {
13
+
14
+ override fun getEventName(): String {
15
+ return EVENT_NAME
16
+ }
17
+
18
+ override fun getEventData(): WritableMap {
19
+ val eventData = Arguments.createMap()
20
+
21
+ // Remove zero-width spaces React Native inserts sometimes
22
+ val normalizedText = text.replace(Regex("\\u200B"), "")
23
+
24
+ eventData.putString("value", normalizedText)
25
+ return eventData
26
+ }
27
+
28
+ override fun experimental_isSynchronous(): Boolean {
29
+ return experimentalSynchronousEvents
30
+ }
31
+
32
+ companion object {
33
+ const val EVENT_NAME = "onChangeText"
34
+ }
35
+ }
@@ -0,0 +1,27 @@
1
+ package com.typerich.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ class OnInputBlurEvent(surfaceId: Int, viewId: Int, private val experimentalSynchronousEvents: Boolean) :
8
+ Event<OnInputBlurEvent>(surfaceId, viewId) {
9
+
10
+ override fun getEventName(): String {
11
+ return EVENT_NAME
12
+ }
13
+
14
+ override fun getEventData(): WritableMap {
15
+ val eventData: WritableMap = Arguments.createMap()
16
+
17
+ return eventData
18
+ }
19
+
20
+ override fun experimental_isSynchronous(): Boolean {
21
+ return experimentalSynchronousEvents
22
+ }
23
+
24
+ companion object {
25
+ const val EVENT_NAME: String = "onInputBlur"
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ package com.typerich.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ class OnInputFocusEvent(surfaceId: Int, viewId: Int, private val experimentalSynchronousEvents: Boolean) :
8
+ Event<OnInputFocusEvent>(surfaceId, viewId) {
9
+
10
+ override fun getEventName(): String {
11
+ return EVENT_NAME
12
+ }
13
+
14
+ override fun getEventData(): WritableMap {
15
+ val eventData: WritableMap = Arguments.createMap()
16
+
17
+ return eventData
18
+ }
19
+
20
+ override fun experimental_isSynchronous(): Boolean {
21
+ return experimentalSynchronousEvents
22
+ }
23
+
24
+ companion object {
25
+ const val EVENT_NAME: String = "onInputFocus"
26
+ }
27
+ }
@@ -0,0 +1,45 @@
1
+ package com.typerich.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ class OnPasteImageEvent(
8
+ surfaceId: Int,
9
+ viewId: Int,
10
+ private val uri: String,
11
+ private val type: String,
12
+ private val fileName: String,
13
+ private val fileSize: Double, // RN Int32 maps to Kotlin Int
14
+ private val errorMessage: String? = null,
15
+ private val experimentalSynchronousEvents: Boolean
16
+ ) : Event<OnPasteImageEvent>(surfaceId, viewId) {
17
+
18
+ override fun getEventName() = EVENT_NAME
19
+ override fun canCoalesce() = false
20
+
21
+ override fun getEventData(): WritableMap {
22
+ val map = Arguments.createMap()
23
+
24
+ map.putString("uri", uri)
25
+ map.putString("type", type)
26
+ map.putString("fileName", fileName)
27
+ map.putDouble("fileSize", fileSize)
28
+
29
+ if (errorMessage != null) {
30
+ val errorMap = Arguments.createMap()
31
+ errorMap.putString("message", errorMessage)
32
+ map.putMap("error", errorMap)
33
+ }
34
+
35
+ return map
36
+ }
37
+
38
+ override fun experimental_isSynchronous(): Boolean {
39
+ return experimentalSynchronousEvents
40
+ }
41
+
42
+ companion object {
43
+ const val EVENT_NAME = "onPasteImage"
44
+ }
45
+ }
@@ -0,0 +1,73 @@
1
+ cmake_minimum_required(VERSION 3.13)
2
+ set(CMAKE_VERBOSE_MAKEFILE on)
3
+
4
+ # The JS spec name → codegen outputs react_codegen_<name>
5
+ set(LIB_SPEC_LITERAL TypeRichTextInputViewSpec)
6
+
7
+ # Your actual custom C++ folder name
8
+ set(LIB_CUSTOM_LITERAL TypeRichTextInputView)
9
+
10
+ set(LIB_TARGET_NAME react_codegen_${LIB_SPEC_LITERAL})
11
+
12
+ # Directories
13
+ set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
14
+ set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni)
15
+ set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_SPEC_LITERAL})
16
+
17
+ set(LIB_CUSTOM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/react/renderer/components/${LIB_CUSTOM_LITERAL})
18
+
19
+ # Custom handwritten C++ code
20
+ file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS
21
+ ${LIB_CUSTOM_DIR}/*.cpp
22
+ )
23
+
24
+ # Codegen generated files
25
+ file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS
26
+ ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp
27
+ )
28
+
29
+ add_library(
30
+ ${LIB_TARGET_NAME}
31
+ SHARED
32
+ ${CMAKE_CURRENT_SOURCE_DIR}/TypeRichTextInputViewSpec.cpp
33
+ ${LIB_CUSTOM_SRCS}
34
+ ${LIB_CODEGEN_SRCS}
35
+ )
36
+
37
+ target_include_directories(
38
+ ${LIB_TARGET_NAME}
39
+ PUBLIC
40
+ .
41
+ ${LIB_CUSTOM_DIR}
42
+ ${LIB_ANDROID_GENERATED_JNI_DIR}
43
+ ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}
44
+ )
45
+
46
+ find_package(fbjni REQUIRED CONFIG)
47
+ find_package(ReactAndroid REQUIRED CONFIG)
48
+
49
+ target_link_libraries(
50
+ ${LIB_TARGET_NAME}
51
+ fbjni::fbjni
52
+ ReactAndroid::jsi
53
+ ReactAndroid::reactnative
54
+ log
55
+ )
56
+
57
+ if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
58
+ target_compile_reactnative_options(${LIB_TARGET_NAME} PRIVATE)
59
+ else()
60
+ target_compile_options(
61
+ ${LIB_TARGET_NAME}
62
+ PRIVATE
63
+ -fexceptions
64
+ -frtti
65
+ -Wall
66
+ )
67
+ endif()
68
+
69
+ target_include_directories(
70
+ ${CMAKE_PROJECT_NAME}
71
+ PUBLIC
72
+ ${CMAKE_CURRENT_SOURCE_DIR}
73
+ )
@@ -0,0 +1,22 @@
1
+
2
+ /**
3
+ * This code was generated by
4
+ * [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
5
+ *
6
+ * Do not edit this file as changes may cause incorrect behavior and will be
7
+ * lost once the code is regenerated.
8
+ *
9
+ * @generated by codegen project: GenerateModuleJniCpp.js
10
+ */
11
+
12
+ #include "TypeRichTextInputViewSpec.h"
13
+
14
+ namespace facebook::react {
15
+
16
+ std::shared_ptr<TurboModule> TypeRichTextInputViewSpec_ModuleProvider(
17
+ const std::string &moduleName, const JavaTurboModule::InitParams &params) {
18
+
19
+ return nullptr;
20
+ }
21
+
22
+ } // namespace facebook::react
@@ -0,0 +1,26 @@
1
+
2
+ /**
3
+ * This code was generated by
4
+ * [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
5
+ *
6
+ * Do not edit this file as changes may cause incorrect behavior and will be
7
+ * lost once the code is regenerated.
8
+ *
9
+ * @generated by codegen project: GenerateModuleJniH.js
10
+ */
11
+
12
+ #pragma once
13
+
14
+ #include <ReactCommon/JavaTurboModule.h>
15
+ #include <ReactCommon/TurboModule.h>
16
+ #include <jsi/jsi.h>
17
+
18
+ #include <react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewComponentDescriptor.h>
19
+
20
+ namespace facebook::react {
21
+
22
+ JSI_EXPORT
23
+ std::shared_ptr<TurboModule> TypeRichTextInputViewSpec_ModuleProvider(
24
+ const std::string &moduleName, const JavaTurboModule::InitParams &params);
25
+
26
+ } // namespace facebook::react
@@ -0,0 +1,36 @@
1
+ #pragma once
2
+
3
+ #include "TypeRichTextInputViewMeasurementManager.h"
4
+ #include "TypeRichTextInputViewShadowNode.h"
5
+
6
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
7
+
8
+ namespace facebook::react {
9
+
10
+ class TypeRichTextInputViewComponentDescriptor final
11
+ : public ConcreteComponentDescriptor<TypeRichTextInputViewShadowNode> {
12
+ public:
13
+ TypeRichTextInputViewComponentDescriptor(
14
+ const ComponentDescriptorParameters &parameters)
15
+ : ConcreteComponentDescriptor(parameters),
16
+ measurementsManager_(
17
+ std::make_shared<TypeRichTextInputViewMeasurementManager>(
18
+ contextContainer_)) {}
19
+
20
+ void adopt(ShadowNode &shadowNode) const override {
21
+ ConcreteComponentDescriptor::adopt(shadowNode);
22
+ auto &editorShadowNode =
23
+ static_cast<TypeRichTextInputViewShadowNode &>(shadowNode);
24
+
25
+ // `TypeRichTextInputViewShadowNode` uses
26
+ // `TypeRichTextInputViewMeasurementManager` to provide measurements to
27
+ // Yoga.
28
+ editorShadowNode.setMeasurementsManager(measurementsManager_);
29
+ }
30
+
31
+ private:
32
+ const std::shared_ptr<TypeRichTextInputViewMeasurementManager>
33
+ measurementsManager_;
34
+ };
35
+
36
+ } // namespace facebook::react
@@ -0,0 +1,83 @@
1
+ #include "TypeRichTextInputViewMeasurementManager.h"
2
+ #include "conversions.h"
3
+
4
+ #include <fbjni/fbjni.h>
5
+ #include <react/jni/ReadableNativeMap.h>
6
+ #include <react/renderer/core/conversions.h>
7
+
8
+ using namespace facebook::jni;
9
+
10
+ namespace facebook::react {
11
+
12
+ float TypeRichTextInputViewMeasurementManager::measureSingleLineHeight(
13
+ const TypeRichTextInputViewProps &props) const {
14
+
15
+ // TODO: Proper measurement. Temporary fallback.
16
+ if (props.fontSize > 0) {
17
+ return props.fontSize * 1.2f;
18
+ }
19
+
20
+ return 20.0f;
21
+ }
22
+
23
+ Size TypeRichTextInputViewMeasurementManager::measure(
24
+ SurfaceId surfaceId, int viewTag, const TypeRichTextInputViewProps &props,
25
+ LayoutConstraints layoutConstraints) const {
26
+
27
+ const jni::global_ref<jobject> &fabricUIManager =
28
+ contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
29
+
30
+ static const auto measure =
31
+ facebook::jni::findClassStatic(
32
+ "com/facebook/react/fabric/FabricUIManager")
33
+ ->getMethod<jlong(jint, jstring, ReadableMap::javaobject,
34
+ ReadableMap::javaobject, ReadableMap::javaobject,
35
+ jfloat, jfloat, jfloat, jfloat)>("measure");
36
+
37
+ auto minimumSize = layoutConstraints.minimumSize;
38
+ auto maximumSize = layoutConstraints.maximumSize;
39
+
40
+ // CRITICAL FIX: Clamp maximum height BEFORE measuring if numberOfLines is set
41
+ if (props.numberOfLines > 0 && props.multiline) {
42
+ float lineHeight = measureSingleLineHeight(props);
43
+ // Don't guess padding here — clamp based on content height only.
44
+ float maxAllowedContentHeight = (lineHeight * props.numberOfLines);
45
+
46
+ // If props contains padding you can add it:
47
+ // float paddingTop = props.paddingTop; // if available
48
+ // float paddingBottom = props.paddingBottom;
49
+ // float maxAllowedHeight = paddingTop + paddingBottom +
50
+ // maxAllowedContentHeight;
51
+
52
+ float maxAllowedHeight = maxAllowedContentHeight; // no guessed padding
53
+
54
+ // Clamp the max height constraint (this clamps the content area)
55
+ maximumSize.height = std::min(maximumSize.height, maxAllowedHeight);
56
+ }
57
+
58
+ local_ref<JString> componentName = make_jstring("TypeRichTextInputView");
59
+
60
+ // Prepare extraData map with viewTag
61
+ folly::dynamic extraData = folly::dynamic::object();
62
+ extraData["viewTag"] = viewTag;
63
+ local_ref<ReadableNativeMap::javaobject> extraDataRNM =
64
+ ReadableNativeMap::newObjectCxxArgs(extraData);
65
+ local_ref<ReadableMap::javaobject> extraDataRM =
66
+ make_local(reinterpret_cast<ReadableMap::javaobject>(extraDataRNM.get()));
67
+
68
+ // Prepare layout metrics affecting props
69
+ auto serializedProps = toDynamic(props);
70
+ local_ref<ReadableNativeMap::javaobject> propsRNM =
71
+ ReadableNativeMap::newObjectCxxArgs(serializedProps);
72
+ local_ref<ReadableMap::javaobject> propsRM =
73
+ make_local(reinterpret_cast<ReadableMap::javaobject>(propsRNM.get()));
74
+
75
+ auto measurement = yogaMeassureToSize(
76
+ measure(fabricUIManager, surfaceId, componentName.get(),
77
+ extraDataRM.get(), propsRM.get(), nullptr, minimumSize.width,
78
+ maximumSize.width, minimumSize.height, maximumSize.height));
79
+
80
+ return measurement;
81
+ }
82
+
83
+ } // namespace facebook::react
@@ -0,0 +1,25 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/TypeRichTextInputViewSpec/Props.h>
4
+ #include <react/renderer/core/LayoutConstraints.h>
5
+ #include <react/utils/ContextContainer.h>
6
+
7
+ namespace facebook::react {
8
+
9
+ class TypeRichTextInputViewMeasurementManager {
10
+ public:
11
+ TypeRichTextInputViewMeasurementManager(
12
+ const std::shared_ptr<const ContextContainer> &contextContainer)
13
+ : contextContainer_(contextContainer) {}
14
+
15
+ Size measure(SurfaceId surfaceId, int viewTag,
16
+ const TypeRichTextInputViewProps &props,
17
+ LayoutConstraints layoutConstraints) const;
18
+
19
+ float measureSingleLineHeight(const TypeRichTextInputViewProps &props) const;
20
+
21
+ private:
22
+ const std::shared_ptr<const ContextContainer> contextContainer_;
23
+ };
24
+
25
+ } // namespace facebook::react
@@ -0,0 +1,132 @@
1
+ #include "TypeRichTextInputViewShadowNode.h"
2
+
3
+ #include "conversions.h"
4
+ #include <android/log.h>
5
+ #include <folly/json.h>
6
+ #include <react/renderer/core/LayoutContext.h>
7
+
8
+ namespace facebook::react {
9
+ extern const char TypeRichTextInputViewComponentName[] =
10
+ "TypeRichTextInputView";
11
+ void TypeRichTextInputViewShadowNode::setMeasurementsManager(
12
+ const std::shared_ptr<TypeRichTextInputViewMeasurementManager>
13
+ &measurementsManager) {
14
+ ensureUnsealed();
15
+ measurementsManager_ = measurementsManager;
16
+ }
17
+
18
+ // Mark layout as dirty after state has been updated
19
+ // Once layout is marked as dirty, `measureContent` will be called in order to
20
+ // recalculate layout
21
+ void TypeRichTextInputViewShadowNode::dirtyLayoutIfNeeded() {
22
+ const auto state = this->getStateData();
23
+ const auto counter = state.getForceHeightRecalculationCounter();
24
+
25
+ if (forceHeightRecalculationCounter_ != counter) {
26
+ forceHeightRecalculationCounter_ = counter;
27
+
28
+ dirtyLayout();
29
+ }
30
+ }
31
+
32
+ Size TypeRichTextInputViewShadowNode::measureContent(
33
+ const LayoutContext &layoutContext,
34
+ const LayoutConstraints &layoutConstraints) const {
35
+
36
+ const auto &props = getConcreteProps();
37
+
38
+ try {
39
+ folly::dynamic dyn = toDynamic(props);
40
+ std::string json = folly::toJson(dyn);
41
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp",
42
+ "toDynamic(props) = %s", json.c_str());
43
+ } catch (const std::exception &e) {
44
+ __android_log_print(ANDROID_LOG_ERROR, "TypeRichCpp",
45
+ "toDynamic() threw: %s", e.what());
46
+ }
47
+ auto size = measurementsManager_->measure(getSurfaceId(), getTag(), props,
48
+ layoutConstraints);
49
+
50
+ float lineHeight = measurementsManager_->measureSingleLineHeight(props);
51
+
52
+ // single line mode
53
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "numberOfLines = %d",
54
+ props.numberOfLines);
55
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "multiline = %s",
56
+ props.multiline ? "true" : "false");
57
+
58
+ if (!props.multiline) {
59
+ size.height = lineHeight;
60
+ return size;
61
+ }
62
+
63
+ // multiline without limit
64
+ if (props.numberOfLines <= 0) {
65
+ return size; // natural Android height
66
+ }
67
+
68
+ // multiline with limit and autogrow
69
+ // Extract padding (React Native provides it inside props.style)
70
+ // Read padding from Fabric LayoutMetrics (RN 0.75+)
71
+ const auto &layoutMetrics = getLayoutMetrics();
72
+ float paddingTop = layoutMetrics.contentInsets.top;
73
+ float paddingBottom = layoutMetrics.contentInsets.bottom;
74
+
75
+ float naturalHeight = size.height;
76
+
77
+ // Remove padding to calculate pure text height
78
+ float contentHeight = naturalHeight - paddingTop - paddingBottom;
79
+ contentHeight = std::max(0.f, contentHeight);
80
+
81
+ // Compute natural line count
82
+ float rawLines = contentHeight / lineHeight;
83
+ int naturalLines = std::max(1, (int)std::floor(rawLines));
84
+
85
+ // Clamp based on numberOfLines
86
+ int finalLines = std::min(naturalLines, props.numberOfLines);
87
+
88
+ // Reapply padding
89
+ size.height = paddingTop + paddingBottom + lineHeight * finalLines;
90
+
91
+ // Handle single line case, bugfix when there is only single line remaining
92
+ // after you delete other lines
93
+ // temp fix might change implementation later
94
+ if (finalLines == 1) {
95
+ size.height = naturalHeight;
96
+ return size;
97
+ }
98
+
99
+ // bugfix height of one line after the numberof lines is reached
100
+ // temp fix might change implementation later
101
+ if (finalLines == props.numberOfLines) {
102
+ size.height = lineHeight * finalLines;
103
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp",
104
+ "size reached finalLines = numberOfLines");
105
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", " size.height = %f",
106
+ size.height);
107
+ return size;
108
+ }
109
+
110
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "naturalHeight = %f",
111
+ naturalHeight);
112
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "contentHeight = %f",
113
+ contentHeight);
114
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "rawLines = %f",
115
+ rawLines);
116
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "naturalLines = %d",
117
+ naturalLines);
118
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "finalLines = %d",
119
+ finalLines);
120
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "size.height = %f",
121
+ size.height);
122
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "lineheight = %f",
123
+ lineHeight);
124
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "paddingTop = %f",
125
+ paddingTop);
126
+ __android_log_print(ANDROID_LOG_INFO, "TypeRichCpp", "paddingBottom = %f",
127
+ paddingBottom);
128
+
129
+ return size;
130
+ }
131
+
132
+ } // namespace facebook::react
@@ -0,0 +1,54 @@
1
+ #pragma once
2
+
3
+ #include "TypeRichTextInputViewMeasurementManager.h"
4
+ #include "TypeRichTextInputViewState.h"
5
+
6
+ #include <react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.h>
7
+ #include <react/renderer/components/TypeRichTextInputViewSpec/Props.h>
8
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
9
+
10
+ namespace facebook::react {
11
+
12
+ JSI_EXPORT extern const char TypeRichTextInputViewComponentName[];
13
+ /*
14
+ * `ShadowNode` for <TypeRichTextInputView> component.
15
+ */
16
+ class TypeRichTextInputViewShadowNode final
17
+ : public ConcreteViewShadowNode<
18
+ TypeRichTextInputViewComponentName, TypeRichTextInputViewProps,
19
+ TypeRichTextInputViewEventEmitter, TypeRichTextInputViewState> {
20
+ public:
21
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
22
+
23
+ // This constructor is called when we "update" shadow node, e.g. after
24
+ // updating shadow node's state
25
+ TypeRichTextInputViewShadowNode(ShadowNode const &sourceShadowNode,
26
+ ShadowNodeFragment const &fragment)
27
+ : ConcreteViewShadowNode(sourceShadowNode, fragment) {
28
+ dirtyLayoutIfNeeded();
29
+ }
30
+
31
+ static ShadowNodeTraits BaseTraits() {
32
+ auto traits = ConcreteViewShadowNode::BaseTraits();
33
+ traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
34
+ traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
35
+ return traits;
36
+ }
37
+
38
+ // Associates a shared `TypeRichTextInputViewMeasurementManager` with the
39
+ // node.
40
+ void setMeasurementsManager(
41
+ const std::shared_ptr<TypeRichTextInputViewMeasurementManager>
42
+ &measurementsManager);
43
+
44
+ void dirtyLayoutIfNeeded();
45
+
46
+ Size
47
+ measureContent(const LayoutContext &layoutContext,
48
+ const LayoutConstraints &layoutConstraints) const override;
49
+
50
+ private:
51
+ int forceHeightRecalculationCounter_;
52
+ std::shared_ptr<TypeRichTextInputViewMeasurementManager> measurementsManager_;
53
+ };
54
+ } // namespace facebook::react
@@ -0,0 +1,9 @@
1
+ #include "TypeRichTextInputViewState.h"
2
+
3
+ namespace facebook::react {
4
+
5
+ int TypeRichTextInputViewState::getForceHeightRecalculationCounter() const {
6
+ return forceHeightRecalculationCounter_;
7
+ }
8
+
9
+ } // namespace facebook::react
@@ -0,0 +1,28 @@
1
+ #pragma once
2
+
3
+ #include <folly/dynamic.h>
4
+
5
+ namespace facebook::react {
6
+
7
+ class TypeRichTextInputViewState {
8
+ public:
9
+ // match to declaration order
10
+ TypeRichTextInputViewState()
11
+ : lineCount(1), forceHeightRecalculationCounter_(0) {}
12
+
13
+ // Used by Kotlin to set current text value
14
+ TypeRichTextInputViewState(TypeRichTextInputViewState const &previousState,
15
+ folly::dynamic data)
16
+ : lineCount((int)data["lineCount"].getInt()),
17
+ forceHeightRecalculationCounter_(
18
+ (int)data["forceHeightRecalculationCounter"].getInt()) {};
19
+ folly::dynamic getDynamic() const { return {}; };
20
+
21
+ int lineCount;
22
+ int getForceHeightRecalculationCounter() const;
23
+
24
+ private:
25
+ const int forceHeightRecalculationCounter_{};
26
+ };
27
+
28
+ } // namespace facebook::react