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.
- package/LICENSE +28 -0
- package/README.md +37 -0
- package/TypeRichTextInput.podspec +20 -0
- package/android/build.gradle +99 -0
- package/android/generated/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TypeRichTextInputViewManagerDelegate.java +100 -0
- package/android/generated/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TypeRichTextInputViewManagerInterface.java +38 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.cpp +22 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.h +24 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.cpp +70 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.h +59 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/Props.cpp +132 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/Props.h +51 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.cpp +17 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.h +23 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/States.cpp +16 -0
- package/android/generated/android/app/build/generated/source/codegen/jni/react/renderer/components/TypeRichTextInputViewSpec/States.h +20 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/typerich/MeasurementStore.kt +148 -0
- package/android/src/main/java/com/typerich/TypeRichTextInputView.kt +503 -0
- package/android/src/main/java/com/typerich/TypeRichTextInputViewLayoutManager.kt +30 -0
- package/android/src/main/java/com/typerich/TypeRichTextInputViewManager.kt +188 -0
- package/android/src/main/java/com/typerich/TypeRichTextInputViewPackage.kt +19 -0
- package/android/src/main/java/com/typerich/events/OnChangeSelectionEvent.kt +29 -0
- package/android/src/main/java/com/typerich/events/OnChangeTextEvent.kt +35 -0
- package/android/src/main/java/com/typerich/events/OnInputBlurEvent.kt +27 -0
- package/android/src/main/java/com/typerich/events/OnInputFocusEvent.kt +27 -0
- package/android/src/main/java/com/typerich/events/OnPasteImageEvent.kt +45 -0
- package/android/src/main/new_arch/CMakeLists.txt +73 -0
- package/android/src/main/new_arch/TypeRichTextInputViewSpec.cpp +22 -0
- package/android/src/main/new_arch/TypeRichTextInputViewSpec.h +26 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewComponentDescriptor.h +36 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewMeasurementManager.cpp +83 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewMeasurementManager.h +25 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewShadowNode.cpp +132 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewShadowNode.h +54 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewState.cpp +9 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/TypeRichTextInputViewState.h +28 -0
- package/android/src/main/new_arch/react/renderer/components/TypeRichTextInputView/conversions.h +21 -0
- package/ios/TypeRichTextInputView.h +14 -0
- package/ios/TypeRichTextInputView.mm +71 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.cpp +22 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ComponentDescriptors.h +24 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.cpp +70 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.h +59 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/Props.cpp +132 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/Props.h +51 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/RCTComponentViewHelpers.h +80 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.cpp +17 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/ShadowNodes.h +23 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/States.cpp +16 -0
- package/ios/generated/build/generated/ios/react/renderer/components/TypeRichTextInputViewSpec/States.h +20 -0
- package/lib/module/TypeRichTextInput.js +50 -0
- package/lib/module/TypeRichTextInput.js.map +1 -0
- package/lib/module/TypeRichTextInputNativeComponent.ts +92 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types/react-native-codegen.d.js +2 -0
- package/lib/module/types/react-native-codegen.d.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/TypeRichTextInput.d.ts +35 -0
- package/lib/typescript/src/TypeRichTextInput.d.ts.map +1 -0
- package/lib/typescript/src/TypeRichTextInputNativeComponent.d.ts +57 -0
- package/lib/typescript/src/TypeRichTextInputNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +180 -0
- package/react-native.config.js +13 -0
- package/src/TypeRichTextInput.tsx +115 -0
- package/src/TypeRichTextInputNativeComponent.ts +92 -0
- package/src/index.tsx +6 -0
- 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 ¶ms) {
|
|
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 ¶ms);
|
|
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 ¶meters)
|
|
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,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
|