@whetware/react-native-stroke-text 0.0.11 → 0.0.13
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/CHANGELOG.md +8 -0
- package/android/src/main/cpp/cpp-adapter.cpp +4 -1
- package/android/src/main/java/com/margelo/nitro/stroketext/HybridStrokeTextView.kt +5 -11
- package/android/src/main/java/com/margelo/nitro/stroketext/NitroStrokeTextPackage.kt +2 -2
- package/android/src/main/java/com/margelo/nitro/stroketext/StrokeTextView.kt +8 -17
- package/lib/StrokeText.js +22 -1
- package/nitro.json +8 -2
- package/nitrogen/generated/android/NitroStrokeTextOnLoad.cpp +27 -17
- package/nitrogen/generated/android/NitroStrokeTextOnLoad.hpp +13 -4
- package/nitrogen/generated/android/c++/JHybridStrokeTextViewSpec.cpp +72 -78
- package/nitrogen/generated/android/c++/JHybridStrokeTextViewSpec.hpp +19 -22
- package/nitrogen/generated/android/c++/JStrokeTextAlign.hpp +2 -2
- package/nitrogen/generated/android/c++/JStrokeTextAlignVertical.hpp +2 -2
- package/nitrogen/generated/android/c++/JStrokeTextDecorationLine.hpp +2 -2
- package/nitrogen/generated/android/c++/JStrokeTextEllipsizeMode.hpp +2 -2
- package/nitrogen/generated/android/c++/JStrokeTextFontStyle.hpp +2 -2
- package/nitrogen/generated/android/c++/JStrokeTextTransform.hpp +2 -2
- package/nitrogen/generated/android/c++/views/JHybridStrokeTextViewStateUpdater.cpp +94 -94
- package/nitrogen/generated/android/c++/views/JHybridStrokeTextViewStateUpdater.hpp +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/stroketext/HybridStrokeTextViewSpec.kt +16 -18
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/stroketext/views/HybridStrokeTextViewManager.kt +13 -3
- package/nitrogen/generated/ios/NitroStrokeText+autolinking.rb +2 -0
- package/nitrogen/generated/ios/NitroStrokeText-Swift-Cxx-Bridge.hpp +9 -9
- package/nitrogen/generated/ios/c++/views/HybridStrokeTextViewComponent.mm +15 -0
- package/nitrogen/generated/ios/swift/HybridStrokeTextViewSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridStrokeTextViewSpec_cxx.swift +147 -46
- package/nitrogen/generated/shared/c++/views/HybridStrokeTextViewComponent.cpp +5 -36
- package/nitrogen/generated/shared/c++/views/HybridStrokeTextViewComponent.hpp +8 -5
- package/package.json +10 -10
- package/android/src/main/java/com/margelo/nitro/stroketext/views/StrokeTextViewManager.kt +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @whetware/react-native-stroke-text
|
|
2
2
|
|
|
3
|
+
## 0.0.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`f94116e`](https://github.com/whetware/react-native-stroke-text/commit/f94116e693d2ee77e643d952f6943728e9d52c25) Thanks [@evelant](https://github.com/evelant)! - Fix Android stroke-text wrapping by measuring the outline inset as part of layout, drawing the RN-measured line breaks in the native overlay, aligning native text metrics with React Native Text, and preserving separate fill and outline colors.
|
|
8
|
+
|
|
9
|
+
Regenerate Nitro native bindings with Nitro/Nitrogen 0.36.1 so the Android C++ and Kotlin code builds with React Native 0.86 / Expo 57, including fbjni's current `HybridClass` requirements.
|
|
10
|
+
|
|
3
11
|
## 0.0.6
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#include <jni.h>
|
|
2
|
+
#include <fbjni/fbjni.h>
|
|
2
3
|
#include "NitroStrokeTextOnLoad.hpp"
|
|
3
4
|
|
|
4
5
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
|
|
5
|
-
return
|
|
6
|
+
return facebook::jni::initialize(vm, []() {
|
|
7
|
+
margelo::nitro::stroketext::registerAllNatives();
|
|
8
|
+
});
|
|
6
9
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
package com.margelo.nitro.stroketext
|
|
2
2
|
|
|
3
3
|
import android.view.View
|
|
4
|
-
import com.facebook.jni.HybridData
|
|
5
4
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
5
|
+
import com.margelo.nitro.R.id.associated_hybrid_view_tag
|
|
6
6
|
import kotlin.math.ceil
|
|
7
7
|
|
|
8
8
|
class HybridStrokeTextView(context: ThemedReactContext) : HybridStrokeTextViewSpec() {
|
|
@@ -43,17 +43,11 @@ class HybridStrokeTextView(context: ThemedReactContext) : HybridStrokeTextViewSp
|
|
|
43
43
|
if (isDisposed) return
|
|
44
44
|
isDisposed = true
|
|
45
45
|
super.dispose()
|
|
46
|
+
}
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
val hybridData = hybridDataField.get(this) as? HybridData ?: return
|
|
51
|
-
|
|
52
|
-
val resetNativeMethod = HybridData::class.java.getDeclaredMethod("resetNative")
|
|
53
|
-
resetNativeMethod.isAccessible = true
|
|
54
|
-
resetNativeMethod.invoke(hybridData)
|
|
55
|
-
} catch (_: Throwable) {
|
|
56
|
-
}
|
|
48
|
+
override fun onDropView() {
|
|
49
|
+
strokeTextView.setTag(associated_hybrid_view_tag, null)
|
|
50
|
+
dispose()
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
override fun afterUpdate() {
|
|
@@ -7,12 +7,12 @@ import com.facebook.react.BaseReactPackage
|
|
|
7
7
|
import com.facebook.react.ViewManagerOnDemandReactPackage
|
|
8
8
|
import com.facebook.react.bridge.ModuleSpec
|
|
9
9
|
import com.facebook.react.uimanager.ViewManager
|
|
10
|
-
import com.margelo.nitro.stroketext.views.
|
|
10
|
+
import com.margelo.nitro.stroketext.views.HybridStrokeTextViewManager
|
|
11
11
|
|
|
12
12
|
class NitroStrokeTextPackage : BaseReactPackage(), ViewManagerOnDemandReactPackage {
|
|
13
13
|
private val viewManagers: Map<String, ModuleSpec> by lazy {
|
|
14
14
|
mapOf(
|
|
15
|
-
"StrokeTextView" to ModuleSpec.viewManagerSpec {
|
|
15
|
+
"StrokeTextView" to ModuleSpec.viewManagerSpec { HybridStrokeTextViewManager() }
|
|
16
16
|
)
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -5,6 +5,7 @@ import android.graphics.Color
|
|
|
5
5
|
import android.graphics.Paint
|
|
6
6
|
import android.graphics.Paint.FontMetricsInt
|
|
7
7
|
import android.graphics.Typeface
|
|
8
|
+
import android.content.res.ColorStateList
|
|
8
9
|
import android.os.Build
|
|
9
10
|
import android.text.Layout
|
|
10
11
|
import android.text.TextDirectionHeuristics
|
|
@@ -71,9 +72,9 @@ internal class StrokeTextView(context: ThemedReactContext) : TextView(context) {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
override fun onDraw(canvas: Canvas) {
|
|
74
|
-
// Draw stroke behind fill
|
|
75
|
-
//
|
|
76
|
-
|
|
75
|
+
// Draw stroke behind fill through TextView's normal drawing path. Calling super.onDraw()
|
|
76
|
+
// for both passes keeps Android's TextView layout, glyph shaping, and color state handling
|
|
77
|
+
// consistent with the fill render while still letting us switch the paint style for outline.
|
|
77
78
|
if (layout != null && strokeWidthPx > 0f && strokeColor != Color.TRANSPARENT) {
|
|
78
79
|
val textPaint = paint
|
|
79
80
|
val prevStyle = textPaint.style
|
|
@@ -81,29 +82,23 @@ internal class StrokeTextView(context: ThemedReactContext) : TextView(context) {
|
|
|
81
82
|
val prevStrokeJoin = textPaint.strokeJoin
|
|
82
83
|
val prevStrokeCap = textPaint.strokeCap
|
|
83
84
|
val prevColor = textPaint.color
|
|
85
|
+
val prevTextColors: ColorStateList = textColors
|
|
84
86
|
val prevUnderline = textPaint.isUnderlineText
|
|
85
87
|
val prevStrike = textPaint.isStrikeThruText
|
|
86
88
|
|
|
87
|
-
val saveCount = canvas.save()
|
|
88
|
-
val compoundPaddingLeft = compoundPaddingLeft
|
|
89
|
-
val extendedPaddingTop = extendedPaddingTop
|
|
90
|
-
|
|
91
|
-
canvas.translate(compoundPaddingLeft.toFloat(), extendedPaddingTop.toFloat())
|
|
92
|
-
canvas.translate(-scrollX.toFloat(), -scrollY.toFloat())
|
|
93
|
-
|
|
94
89
|
// Only stroke the glyph outlines; keep underline/strike in the fill pass.
|
|
95
90
|
textPaint.isUnderlineText = false
|
|
96
91
|
textPaint.isStrikeThruText = false
|
|
97
92
|
|
|
93
|
+
setTextColor(strokeColor)
|
|
98
94
|
textPaint.style = Paint.Style.STROKE
|
|
99
95
|
textPaint.strokeJoin = Paint.Join.ROUND
|
|
100
96
|
textPaint.strokeCap = Paint.Cap.ROUND
|
|
101
97
|
textPaint.strokeWidth = strokeWidthPx
|
|
102
98
|
textPaint.color = strokeColor
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
canvas.restoreToCount(saveCount)
|
|
99
|
+
super.onDraw(canvas)
|
|
106
100
|
|
|
101
|
+
setTextColor(prevTextColors)
|
|
107
102
|
textPaint.style = prevStyle
|
|
108
103
|
textPaint.strokeWidth = prevStrokeWidth
|
|
109
104
|
textPaint.strokeJoin = prevStrokeJoin
|
|
@@ -196,10 +191,6 @@ internal class StrokeTextView(context: ThemedReactContext) : TextView(context) {
|
|
|
196
191
|
|
|
197
192
|
// Line limits / ellipsizing
|
|
198
193
|
val maxLines = if (numberOfLines > 0) numberOfLines else Int.MAX_VALUE
|
|
199
|
-
// React Native's single-line Text does not wrap at spaces. Without horizontal scrolling,
|
|
200
|
-
// Android TextView can create an internal second line inside a host view that was measured
|
|
201
|
-
// as one line by the hidden RN Text used for layout.
|
|
202
|
-
setHorizontallyScrolling(numberOfLines == 1)
|
|
203
194
|
setMaxLines(maxLines)
|
|
204
195
|
ellipsize =
|
|
205
196
|
if (numberOfLines <= 0) {
|
package/lib/StrokeText.js
CHANGED
|
@@ -114,6 +114,12 @@ export function StrokeText({ text, children, style, hybridRef, ...rest }) {
|
|
|
114
114
|
const [measuredNativeText, setMeasuredNativeText] = React.useState(undefined);
|
|
115
115
|
const nativeText = measuredNativeText ?? resolvedText;
|
|
116
116
|
const nativeTextTransform = measuredNativeText == null ? effectiveTextTransform : 'none';
|
|
117
|
+
// RN's hidden Text owns measurement, but Android TextView gets its own layout pass.
|
|
118
|
+
// Compensate for the native stroke inset on every edge, then give that native
|
|
119
|
+
// pass extra right-side room so one-pixel/font-metric drift cannot turn an RN
|
|
120
|
+
// single line into a native soft wrap.
|
|
121
|
+
const nativeOverlayInset = Platform.OS === 'android' && strokeInset > 0 ? strokeInset : 0;
|
|
122
|
+
const nativeOverlayRightInset = nativeOverlayInset > 0 ? nativeOverlayInset * 2 : 0;
|
|
117
123
|
const wrappedHybridRef = React.useMemo(() => (hybridRef ? callback(hybridRef) : undefined), [hybridRef]);
|
|
118
124
|
React.useEffect(() => {
|
|
119
125
|
setMeasuredNativeText(undefined);
|
|
@@ -141,6 +147,11 @@ export function StrokeText({ text, children, style, hybridRef, ...rest }) {
|
|
|
141
147
|
const handleTextLayout = React.useCallback((event) => {
|
|
142
148
|
if (!shouldSyncMeasuredLineBreaks)
|
|
143
149
|
return;
|
|
150
|
+
const lineCount = event.nativeEvent.lines.length;
|
|
151
|
+
if (lineCount <= 1) {
|
|
152
|
+
setMeasuredNativeText((currentText) => currentText == null ? currentText : undefined);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
144
155
|
const nextText = toNativeMeasuredText(event.nativeEvent.lines);
|
|
145
156
|
if (nextText == null)
|
|
146
157
|
return;
|
|
@@ -189,7 +200,17 @@ export function StrokeText({ text, children, style, hybridRef, ...rest }) {
|
|
|
189
200
|
},
|
|
190
201
|
styles.hiddenText,
|
|
191
202
|
] }, resolvedText),
|
|
192
|
-
React.createElement(NativeStrokeTextView, { ...nativeProps, text: nativeText, color: effectiveColor, fontSize: effectiveFontSize, fontWeight: effectiveFontWeight, fontFamily: effectiveFontFamily, fontStyle: effectiveFontStyle, lineHeight: effectiveLineHeight, letterSpacing: effectiveLetterSpacing, textAlign: effectiveTextAlign, textAlignVertical: effectiveTextAlignVertical, textDecorationLine: effectiveTextDecorationLine, textTransform: nativeTextTransform, opacity: nativeProps.opacity ?? toNumber(styleOpacity), includeFontPadding: effectiveIncludeFontPadding, numberOfLines: nativeProps.numberOfLines, ellipsizeMode: effectiveEllipsizeMode, paddingTop: baseTop, paddingRight: baseRight, paddingBottom: baseBottom, paddingLeft: baseLeft, hybridRef: wrappedHybridRef, pointerEvents: "none", style:
|
|
203
|
+
React.createElement(NativeStrokeTextView, { ...nativeProps, text: nativeText, color: effectiveColor, fontSize: effectiveFontSize, fontWeight: effectiveFontWeight, fontFamily: effectiveFontFamily, fontStyle: effectiveFontStyle, lineHeight: effectiveLineHeight, letterSpacing: effectiveLetterSpacing, textAlign: effectiveTextAlign, textAlignVertical: effectiveTextAlignVertical, textDecorationLine: effectiveTextDecorationLine, textTransform: nativeTextTransform, opacity: nativeProps.opacity ?? toNumber(styleOpacity), includeFontPadding: effectiveIncludeFontPadding, numberOfLines: nativeProps.numberOfLines, ellipsizeMode: effectiveEllipsizeMode, paddingTop: baseTop, paddingRight: baseRight, paddingBottom: baseBottom, paddingLeft: baseLeft, hybridRef: wrappedHybridRef, pointerEvents: "none", style: [
|
|
204
|
+
styles.overlay,
|
|
205
|
+
nativeOverlayInset > 0
|
|
206
|
+
? {
|
|
207
|
+
top: -nativeOverlayInset,
|
|
208
|
+
right: -nativeOverlayRightInset,
|
|
209
|
+
bottom: -nativeOverlayInset,
|
|
210
|
+
left: -nativeOverlayInset,
|
|
211
|
+
}
|
|
212
|
+
: null,
|
|
213
|
+
] })));
|
|
193
214
|
}
|
|
194
215
|
const styles = StyleSheet.create({
|
|
195
216
|
container: {},
|
package/nitro.json
CHANGED
|
@@ -14,8 +14,14 @@
|
|
|
14
14
|
},
|
|
15
15
|
"autolinking": {
|
|
16
16
|
"StrokeTextView": {
|
|
17
|
-
"
|
|
18
|
-
|
|
17
|
+
"ios": {
|
|
18
|
+
"language": "swift",
|
|
19
|
+
"implementationClassName": "HybridStrokeTextView"
|
|
20
|
+
},
|
|
21
|
+
"android": {
|
|
22
|
+
"language": "kotlin",
|
|
23
|
+
"implementationClassName": "HybridStrokeTextView"
|
|
24
|
+
}
|
|
19
25
|
}
|
|
20
26
|
},
|
|
21
27
|
"ignorePaths": [
|
|
@@ -22,25 +22,35 @@
|
|
|
22
22
|
namespace margelo::nitro::stroketext {
|
|
23
23
|
|
|
24
24
|
int initialize(JavaVM* vm) {
|
|
25
|
+
return facebook::jni::initialize(vm, []() {
|
|
26
|
+
::margelo::nitro::stroketext::registerAllNatives();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
struct JHybridStrokeTextViewSpecImpl: public jni::JavaClass<JHybridStrokeTextViewSpecImpl, JHybridStrokeTextViewSpec::JavaPart> {
|
|
31
|
+
static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/stroketext/HybridStrokeTextView;";
|
|
32
|
+
static std::shared_ptr<JHybridStrokeTextViewSpec> create() {
|
|
33
|
+
static const auto constructorFn = javaClassStatic()->getConstructor<JHybridStrokeTextViewSpecImpl::javaobject()>();
|
|
34
|
+
jni::local_ref<JHybridStrokeTextViewSpec::JavaPart> javaPart = javaClassStatic()->newObject(constructorFn);
|
|
35
|
+
return javaPart->getJHybridStrokeTextViewSpec();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
void registerAllNatives() {
|
|
25
40
|
using namespace margelo::nitro;
|
|
26
41
|
using namespace margelo::nitro::stroketext;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
auto instance = object.create();
|
|
40
|
-
return instance->cthis()->shared();
|
|
41
|
-
}
|
|
42
|
-
);
|
|
43
|
-
});
|
|
42
|
+
|
|
43
|
+
// Register native JNI methods
|
|
44
|
+
margelo::nitro::stroketext::JHybridStrokeTextViewSpec::CxxPart::registerNatives();
|
|
45
|
+
margelo::nitro::stroketext::views::JHybridStrokeTextViewStateUpdater::registerNatives();
|
|
46
|
+
|
|
47
|
+
// Register Nitro Hybrid Objects
|
|
48
|
+
HybridObjectRegistry::registerHybridObjectConstructor(
|
|
49
|
+
"StrokeTextView",
|
|
50
|
+
[]() -> std::shared_ptr<HybridObject> {
|
|
51
|
+
return JHybridStrokeTextViewSpecImpl::create();
|
|
52
|
+
}
|
|
53
|
+
);
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
} // namespace margelo::nitro::stroketext
|
|
@@ -6,20 +6,29 @@
|
|
|
6
6
|
///
|
|
7
7
|
|
|
8
8
|
#include <jni.h>
|
|
9
|
+
#include <functional>
|
|
9
10
|
#include <NitroModules/NitroDefines.hpp>
|
|
10
11
|
|
|
11
12
|
namespace margelo::nitro::stroketext {
|
|
12
13
|
|
|
14
|
+
[[deprecated("Use registerNatives() instead.")]]
|
|
15
|
+
int initialize(JavaVM* vm);
|
|
16
|
+
|
|
13
17
|
/**
|
|
14
|
-
*
|
|
15
|
-
* Call this in your `JNI_OnLoad` function (probably inside `cpp-adapter.cpp`)
|
|
18
|
+
* Register the native (C++) part of NitroStrokeText, and autolinks all Hybrid Objects.
|
|
19
|
+
* Call this in your `JNI_OnLoad` function (probably inside `cpp-adapter.cpp`),
|
|
20
|
+
* inside a `facebook::jni::initialize(vm, ...)` call.
|
|
16
21
|
* Example:
|
|
17
22
|
* ```cpp (cpp-adapter.cpp)
|
|
18
23
|
* JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
|
|
19
|
-
* return
|
|
24
|
+
* return facebook::jni::initialize(vm, []() {
|
|
25
|
+
* // register all NitroStrokeText HybridObjects
|
|
26
|
+
* margelo::nitro::stroketext::registerNatives();
|
|
27
|
+
* // any other custom registrations go here.
|
|
28
|
+
* });
|
|
20
29
|
* }
|
|
21
30
|
* ```
|
|
22
31
|
*/
|
|
23
|
-
|
|
32
|
+
void registerAllNatives();
|
|
24
33
|
|
|
25
34
|
} // namespace margelo::nitro::stroketext
|