@expensify/react-native-live-markdown 0.1.329 → 0.1.331
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/README.md +1 -1
- package/android/build.gradle +2 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/81/com/expensify/livemarkdown/CustomFabricUIManager.java +121 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/com/expensify/livemarkdown/CustomFabricUIManager.java +4 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ npx expo install @expensify/react-native-live-markdown react-native-worklets exp
|
|
|
23
23
|
React Native Live Markdown requires [react-native-worklets](https://github.com/software-mansion/react-native-reanimated/tree/main/packages/react-native-worklets) 0.7.0 or newer as well as [expensify-common](https://github.com/Expensify/expensify-common) 2.0.115 and [html-entities](https://github.com/mdevils/html-entities) 2.5.3 exactly if using the default built-in ExpensiMark parser.
|
|
24
24
|
|
|
25
25
|
> [!IMPORTANT]
|
|
26
|
-
> Please follow the `react-native-worklets` [Getting Started](https://docs.swmansion.com/react-native-worklets/docs/#react-native-community-cli) guide to avoid issues.
|
|
26
|
+
> Please follow the `react-native-worklets` [Getting Started](https://docs.swmansion.com/react-native-worklets/docs/fundamentals/getting-started/#react-native-community-cli) guide to avoid issues.
|
|
27
27
|
|
|
28
28
|
Then, install the iOS dependencies with CocoaPods:
|
|
29
29
|
|
package/android/build.gradle
CHANGED
|
@@ -129,6 +129,8 @@ android {
|
|
|
129
129
|
java.srcDirs += "src/reactNativeVersionPatch/CustomMountingManager/79"
|
|
130
130
|
} else if (REACT_NATIVE_MINOR_VERSION == 80) {
|
|
131
131
|
java.srcDirs += "src/reactNativeVersionPatch/CustomMountingManager/80"
|
|
132
|
+
} else if (REACT_NATIVE_MINOR_VERSION <= 85) {
|
|
133
|
+
java.srcDirs += "src/reactNativeVersionPatch/CustomMountingManager/81"
|
|
132
134
|
} else {
|
|
133
135
|
java.srcDirs += "src/reactNativeVersionPatch/CustomMountingManager/latest"
|
|
134
136
|
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
package com.expensify.livemarkdown;
|
|
2
|
+
|
|
3
|
+
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaMeasureMode;
|
|
4
|
+
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaSize;
|
|
5
|
+
|
|
6
|
+
import android.text.SpannableStringBuilder;
|
|
7
|
+
|
|
8
|
+
import androidx.annotation.Nullable;
|
|
9
|
+
|
|
10
|
+
import com.facebook.infer.annotation.Assertions;
|
|
11
|
+
import com.facebook.jni.annotations.DoNotStrip;
|
|
12
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
13
|
+
import com.facebook.react.bridge.ReactContext;
|
|
14
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
15
|
+
import com.facebook.react.common.mapbuffer.ReadableMapBuffer;
|
|
16
|
+
import com.facebook.react.fabric.FabricUIManager;
|
|
17
|
+
import com.facebook.react.fabric.mounting.MountingManager;
|
|
18
|
+
import com.facebook.react.fabric.mounting.SurfaceMountingManager;
|
|
19
|
+
import com.facebook.react.uimanager.ViewManagerRegistry;
|
|
20
|
+
import com.facebook.react.uimanager.events.BatchEventDispatchedListener;
|
|
21
|
+
import com.facebook.react.views.text.TextLayoutManager;
|
|
22
|
+
|
|
23
|
+
import java.lang.reflect.Field;
|
|
24
|
+
|
|
25
|
+
@DoNotStrip
|
|
26
|
+
public class CustomFabricUIManager extends FabricUIManager {
|
|
27
|
+
|
|
28
|
+
private final ReactApplicationContext mReactApplicationContext;
|
|
29
|
+
private final MountingManager mMountingManager;
|
|
30
|
+
private final MarkdownUtils mMarkdownUtils;
|
|
31
|
+
|
|
32
|
+
public CustomFabricUIManager(
|
|
33
|
+
ReactApplicationContext reactContext,
|
|
34
|
+
ViewManagerRegistry viewManagerRegistry,
|
|
35
|
+
BatchEventDispatchedListener batchEventDispatchedListener,
|
|
36
|
+
MountingManager mountingManager,
|
|
37
|
+
ReadableMap markdownProps,
|
|
38
|
+
int parserId
|
|
39
|
+
) {
|
|
40
|
+
super(reactContext, viewManagerRegistry, batchEventDispatchedListener);
|
|
41
|
+
|
|
42
|
+
this.mReactApplicationContext = reactContext;
|
|
43
|
+
this.mMountingManager = mountingManager;
|
|
44
|
+
|
|
45
|
+
this.mMarkdownUtils = new MarkdownUtils(reactContext);
|
|
46
|
+
this.mMarkdownUtils.setMarkdownStyle(new MarkdownStyle(markdownProps, reactContext));
|
|
47
|
+
this.mMarkdownUtils.setParserId(parserId);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Override
|
|
51
|
+
public long measureText(
|
|
52
|
+
int surfaceId,
|
|
53
|
+
ReadableMapBuffer attributedString,
|
|
54
|
+
ReadableMapBuffer paragraphAttributes,
|
|
55
|
+
float minWidth,
|
|
56
|
+
float maxWidth,
|
|
57
|
+
float minHeight,
|
|
58
|
+
float maxHeight,
|
|
59
|
+
@Nullable float[] attachmentsPositions) {
|
|
60
|
+
|
|
61
|
+
ReactContext context;
|
|
62
|
+
if (surfaceId > 0) {
|
|
63
|
+
SurfaceMountingManager surfaceMountingManager =
|
|
64
|
+
mMountingManager.getSurfaceManagerEnforced(surfaceId, "measureText");
|
|
65
|
+
if (surfaceMountingManager.isStopped()) {
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
context = surfaceMountingManager.getContext();
|
|
69
|
+
Assertions.assertNotNull(
|
|
70
|
+
context, "Context in SurfaceMountingManager is null. surfaceId: " + surfaceId);
|
|
71
|
+
} else {
|
|
72
|
+
context = mReactApplicationContext;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return TextLayoutManager.measureText(
|
|
76
|
+
context,
|
|
77
|
+
attributedString,
|
|
78
|
+
paragraphAttributes,
|
|
79
|
+
getYogaSize(minWidth, maxWidth),
|
|
80
|
+
getYogaMeasureMode(minWidth, maxWidth),
|
|
81
|
+
getYogaSize(minHeight, maxHeight),
|
|
82
|
+
getYogaMeasureMode(minHeight, maxHeight),
|
|
83
|
+
spannable -> {
|
|
84
|
+
mMarkdownUtils.applyMarkdownFormatting((SpannableStringBuilder)spannable);
|
|
85
|
+
},
|
|
86
|
+
attachmentsPositions);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId) {
|
|
90
|
+
try {
|
|
91
|
+
MountingManager sourceMountingManager = readPrivateField(source, "mMountingManager");
|
|
92
|
+
ReactApplicationContext reactContext = readPrivateField(source, "mReactApplicationContext");
|
|
93
|
+
ViewManagerRegistry viewManagerRegistry = readPrivateField(source, "mViewManagerRegistry");
|
|
94
|
+
BatchEventDispatchedListener batchEventDispatchedListener = readPrivateField(source, "mBatchEventDispatchedListener");
|
|
95
|
+
|
|
96
|
+
FabricUIManager customFabricUIManager = new CustomFabricUIManager(
|
|
97
|
+
reactContext,
|
|
98
|
+
viewManagerRegistry,
|
|
99
|
+
batchEventDispatchedListener,
|
|
100
|
+
sourceMountingManager,
|
|
101
|
+
markdownProps,
|
|
102
|
+
parserId
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return customFabricUIManager;
|
|
106
|
+
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
107
|
+
throw new RuntimeException("[LiveMarkdown] Cannot read data from FabricUIManager", e);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@SuppressWarnings("unchecked")
|
|
112
|
+
private static <T> T readPrivateField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
|
|
113
|
+
Class<?> clazz = obj.getClass();
|
|
114
|
+
|
|
115
|
+
Field field = clazz.getDeclaredField(name);
|
|
116
|
+
field.setAccessible(true);
|
|
117
|
+
T value = (T) field.get(obj);
|
|
118
|
+
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -7,15 +7,11 @@ import android.text.SpannableStringBuilder;
|
|
|
7
7
|
|
|
8
8
|
import androidx.annotation.Nullable;
|
|
9
9
|
|
|
10
|
-
import com.facebook.infer.annotation.Assertions;
|
|
11
10
|
import com.facebook.jni.annotations.DoNotStrip;
|
|
12
11
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
13
|
-
import com.facebook.react.bridge.ReactContext;
|
|
14
12
|
import com.facebook.react.bridge.ReadableMap;
|
|
15
13
|
import com.facebook.react.common.mapbuffer.ReadableMapBuffer;
|
|
16
14
|
import com.facebook.react.fabric.FabricUIManager;
|
|
17
|
-
import com.facebook.react.fabric.mounting.MountingManager;
|
|
18
|
-
import com.facebook.react.fabric.mounting.SurfaceMountingManager;
|
|
19
15
|
import com.facebook.react.uimanager.ViewManagerRegistry;
|
|
20
16
|
import com.facebook.react.uimanager.events.BatchEventDispatchedListener;
|
|
21
17
|
import com.facebook.react.views.text.TextLayoutManager;
|
|
@@ -26,29 +22,26 @@ import java.lang.reflect.Field;
|
|
|
26
22
|
public class CustomFabricUIManager extends FabricUIManager {
|
|
27
23
|
|
|
28
24
|
private final ReactApplicationContext mReactApplicationContext;
|
|
29
|
-
private final MountingManager mMountingManager;
|
|
30
25
|
private final MarkdownUtils mMarkdownUtils;
|
|
31
26
|
|
|
32
27
|
public CustomFabricUIManager(
|
|
33
28
|
ReactApplicationContext reactContext,
|
|
34
29
|
ViewManagerRegistry viewManagerRegistry,
|
|
35
30
|
BatchEventDispatchedListener batchEventDispatchedListener,
|
|
36
|
-
MountingManager mountingManager,
|
|
37
31
|
ReadableMap markdownProps,
|
|
38
32
|
int parserId
|
|
39
33
|
) {
|
|
40
34
|
super(reactContext, viewManagerRegistry, batchEventDispatchedListener);
|
|
41
35
|
|
|
42
36
|
this.mReactApplicationContext = reactContext;
|
|
43
|
-
this.mMountingManager = mountingManager;
|
|
44
37
|
|
|
45
38
|
this.mMarkdownUtils = new MarkdownUtils(reactContext);
|
|
46
39
|
this.mMarkdownUtils.setMarkdownStyle(new MarkdownStyle(markdownProps, reactContext));
|
|
47
40
|
this.mMarkdownUtils.setParserId(parserId);
|
|
48
41
|
}
|
|
49
42
|
|
|
43
|
+
@Override
|
|
50
44
|
public long measureText(
|
|
51
|
-
int surfaceId,
|
|
52
45
|
ReadableMapBuffer attributedString,
|
|
53
46
|
ReadableMapBuffer paragraphAttributes,
|
|
54
47
|
float minWidth,
|
|
@@ -57,22 +50,8 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
57
50
|
float maxHeight,
|
|
58
51
|
@Nullable float[] attachmentsPositions) {
|
|
59
52
|
|
|
60
|
-
ReactContext context;
|
|
61
|
-
if (surfaceId > 0) {
|
|
62
|
-
SurfaceMountingManager surfaceMountingManager =
|
|
63
|
-
mMountingManager.getSurfaceManagerEnforced(surfaceId, "measureText");
|
|
64
|
-
if (surfaceMountingManager.isStopped()) {
|
|
65
|
-
return 0;
|
|
66
|
-
}
|
|
67
|
-
context = surfaceMountingManager.getContext();
|
|
68
|
-
Assertions.assertNotNull(
|
|
69
|
-
context, "Context in SurfaceMountingManager is null. surfaceId: " + surfaceId);
|
|
70
|
-
} else {
|
|
71
|
-
context = mReactApplicationContext;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
53
|
return TextLayoutManager.measureText(
|
|
75
|
-
|
|
54
|
+
mReactApplicationContext.getAssets(),
|
|
76
55
|
attributedString,
|
|
77
56
|
paragraphAttributes,
|
|
78
57
|
getYogaSize(minWidth, maxWidth),
|
|
@@ -86,29 +65,20 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
86
65
|
}
|
|
87
66
|
|
|
88
67
|
public static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId) {
|
|
89
|
-
Class<? extends FabricUIManager> uiManagerClass = source.getClass();
|
|
90
|
-
|
|
91
68
|
try {
|
|
92
|
-
Field mountingManagerField = uiManagerClass.getDeclaredField("mMountingManager");
|
|
93
|
-
mountingManagerField.setAccessible(true);
|
|
94
|
-
|
|
95
|
-
MountingManager sourceMountingManager = readPrivateField(source, "mMountingManager");
|
|
96
69
|
ReactApplicationContext reactContext = readPrivateField(source, "mReactApplicationContext");
|
|
97
70
|
ViewManagerRegistry viewManagerRegistry = readPrivateField(source, "mViewManagerRegistry");
|
|
98
71
|
BatchEventDispatchedListener batchEventDispatchedListener = readPrivateField(source, "mBatchEventDispatchedListener");
|
|
99
72
|
|
|
100
|
-
|
|
73
|
+
return new CustomFabricUIManager(
|
|
101
74
|
reactContext,
|
|
102
75
|
viewManagerRegistry,
|
|
103
76
|
batchEventDispatchedListener,
|
|
104
|
-
sourceMountingManager,
|
|
105
77
|
markdownProps,
|
|
106
78
|
parserId
|
|
107
79
|
);
|
|
108
|
-
|
|
109
|
-
return customFabricUIManager;
|
|
110
80
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
111
|
-
throw new RuntimeException("[LiveMarkdown] Cannot read data from FabricUIManager");
|
|
81
|
+
throw new RuntimeException("[LiveMarkdown] Cannot read data from FabricUIManager", e);
|
|
112
82
|
}
|
|
113
83
|
}
|
|
114
84
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expensify/react-native-live-markdown",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.331",
|
|
4
4
|
"description": "Drop-in replacement for React Native's TextInput component with Markdown formatting.",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|