react-native-enriched-markdown-scaffold 1.0.2-scaffold.6 → 1.0.2-scaffold.8
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/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +2 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +2 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +8 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/events/SelectionChangeEvent.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +16 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/HeadlessActionMode.kt +76 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionChangeReporter.kt +2 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +1 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +1 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +13 -6
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathMeasureHelper.kt +2 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +11 -4
- package/docs/API_REFERENCE.md +4 -2
- package/ios/EnrichedMarkdown.mm +23 -0
- package/ios/EnrichedMarkdownText.mm +21 -0
- package/ios/attachments/ENRMMathInlineAttachment+macOS.m +2 -1
- package/ios/attachments/ENRMMathInlineAttachment.h +3 -0
- package/ios/attachments/ENRMMathInlineAttachment.m +2 -1
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +2 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +2 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +24 -0
- package/ios/internals/MeasurementCache.h +3 -2
- package/ios/math/ENRMRaTeXBridge.swift +23 -5
- package/ios/renderer/ENRMMathInlineRenderer.m +1 -0
- package/ios/styles/StyleConfig.h +4 -0
- package/ios/styles/StyleConfig.mm +24 -0
- package/ios/utils/ENRMLinkChip.m +2 -1
- package/ios/utils/ENRMSelectionChange.h +24 -0
- package/ios/utils/ENRMSelectionChange.m +78 -0
- package/ios/utils/StylePropsUtils.h +10 -0
- package/ios/views/ENRMMathContainerView.m +4 -2
- package/lib/module/EnrichedMarkdownNativeComponent.ts +3 -0
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +3 -0
- package/lib/module/normalizeMarkdownStyle.js +4 -2
- package/lib/module/normalizeMarkdownStyle.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.web.js +4 -2
- package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +3 -0
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +3 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyle.d.ts +22 -0
- package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +2 -0
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.d.ts +8 -2
- package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +8 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/EnrichedMarkdownNativeComponent.ts +3 -0
- package/src/EnrichedMarkdownTextNativeComponent.ts +3 -0
- package/src/normalizeMarkdownStyle.ts +2 -0
- package/src/normalizeMarkdownStyle.web.ts +2 -0
- package/src/types/MarkdownStyle.ts +22 -0
- package/src/types/MarkdownStyleInternal.ts +2 -0
- package/src/types/MarkdownTextProps.ts +8 -2
- package/src/types/events.ts +8 -0
|
@@ -119,6 +119,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
119
119
|
NSArray<NSDictionary *> *_lastLinkLayout;
|
|
120
120
|
|
|
121
121
|
ENRMSelectionChangeReporter *_selectionReporter;
|
|
122
|
+
#if !TARGET_OS_OSX
|
|
123
|
+
ENRMSelectionGestureTracker *_selectionGestures;
|
|
124
|
+
#endif
|
|
122
125
|
|
|
123
126
|
NSLineBreakStrategy _lineBreakStrategy;
|
|
124
127
|
|
|
@@ -300,6 +303,19 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
300
303
|
emitter->onSelectionChange(
|
|
301
304
|
ENRMSelectionChangeEventFromPayload<EnrichedMarkdownTextEventEmitter::OnSelectionChange>(payload));
|
|
302
305
|
}];
|
|
306
|
+
#if !TARGET_OS_OSX
|
|
307
|
+
// A handle drag starting or ending is reported right away, even when the
|
|
308
|
+
// selection itself is unchanged.
|
|
309
|
+
_selectionGestures = [[ENRMSelectionGestureTracker alloc] initWithChange:^{
|
|
310
|
+
EnrichedMarkdownText *strongSelf = weakSelf;
|
|
311
|
+
if (!strongSelf)
|
|
312
|
+
return;
|
|
313
|
+
[strongSelf->_selectionGestures trackTextView:strongSelf->_textView];
|
|
314
|
+
[strongSelf->_selectionReporter forgetLastReported];
|
|
315
|
+
[strongSelf->_selectionReporter flushNow];
|
|
316
|
+
}];
|
|
317
|
+
[_selectionGestures trackTextView:_textView];
|
|
318
|
+
#endif
|
|
303
319
|
}
|
|
304
320
|
|
|
305
321
|
/// The current selection as an `onSelectionChange` payload. Markdown and
|
|
@@ -319,6 +335,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
319
335
|
payload[ENRMSelectionSourceKey] = @"selection";
|
|
320
336
|
payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
|
|
321
337
|
payload[ENRMSelectionWholeKey] = @([selection[ENRMSelectionFullKey] boolValue] && _cachedMarkdown.length > 0);
|
|
338
|
+
payload[ENRMSelectionAdjustingKey] = @(_selectionGestures.adjusting);
|
|
322
339
|
return payload;
|
|
323
340
|
#else
|
|
324
341
|
return ENRMInactiveSelectionPayload();
|
|
@@ -786,6 +803,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
786
803
|
_emitLinkLayout = NO;
|
|
787
804
|
_lastLinkLayout = nil;
|
|
788
805
|
_selectionReporter.enabled = NO;
|
|
806
|
+
#if !TARGET_OS_OSX
|
|
807
|
+
[_selectionGestures reset];
|
|
808
|
+
#endif
|
|
789
809
|
if (_textView != nil) {
|
|
790
810
|
ENRMSetAttributedText(_textView, [[NSAttributedString alloc] initWithString:@""]);
|
|
791
811
|
_textView.hidden = YES;
|
|
@@ -968,6 +988,7 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
968
988
|
|
|
969
989
|
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
970
990
|
{
|
|
991
|
+
[_selectionGestures trackTextView:textView];
|
|
971
992
|
ENRMDismissSelectionEditMenuIfMoved(textView);
|
|
972
993
|
[_selectionReporter selectionChanged:textView.selectedRange.length > 0];
|
|
973
994
|
}
|
|
@@ -14,6 +14,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
14
14
|
/// Typeset the glyphs at bold weight (synthetic — see ENRMRaTeXBridge).
|
|
15
15
|
@property (nonatomic, assign) BOOL bold;
|
|
16
16
|
|
|
17
|
+
/// Ink headroom above and below the formula box (`inlineMath.glyphOverflow`, points).
|
|
18
|
+
@property (nonatomic, assign) CGFloat glyphOverflow;
|
|
19
|
+
|
|
17
20
|
/// YES if block math (`$$...$$`), NO for inline (`$...$`).
|
|
18
21
|
@property (nonatomic, assign) BOOL displayMode;
|
|
19
22
|
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
displayMode:NO
|
|
43
43
|
fontSize:self.fontSize
|
|
44
44
|
color:color
|
|
45
|
-
bold:self.bold
|
|
45
|
+
bold:self.bold
|
|
46
|
+
glyphOverflow:self.glyphOverflow];
|
|
46
47
|
if (!result) {
|
|
47
48
|
_fallbackSource = ENRMMathFallbackString(self.latex, @"$", self.fontSize, color);
|
|
48
49
|
UIFont *font = [_fallbackSource attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL];
|
|
@@ -87,6 +87,7 @@ payload.setProperty(runtime, "whole", event.whole);
|
|
|
87
87
|
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
88
88
|
payload.setProperty(runtime, "endRect", endRect);
|
|
89
89
|
}
|
|
90
|
+
payload.setProperty(runtime, "adjusting", event.adjusting);
|
|
90
91
|
return payload;
|
|
91
92
|
});
|
|
92
93
|
}
|
|
@@ -487,6 +488,7 @@ payload.setProperty(runtime, "whole", event.whole);
|
|
|
487
488
|
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
488
489
|
payload.setProperty(runtime, "endRect", endRect);
|
|
489
490
|
}
|
|
491
|
+
payload.setProperty(runtime, "adjusting", event.adjusting);
|
|
490
492
|
return payload;
|
|
491
493
|
});
|
|
492
494
|
}
|
|
@@ -69,6 +69,7 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
|
|
|
69
69
|
OnSelectionChangeRect rect;
|
|
70
70
|
OnSelectionChangeStartRect startRect;
|
|
71
71
|
OnSelectionChangeEndRect endRect;
|
|
72
|
+
bool adjusting;
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
struct OnTaskListItemPress {
|
|
@@ -395,6 +396,7 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
|
|
|
395
396
|
OnSelectionChangeRect rect;
|
|
396
397
|
OnSelectionChangeStartRect startRect;
|
|
397
398
|
OnSelectionChangeEndRect endRect;
|
|
399
|
+
bool adjusting;
|
|
398
400
|
};
|
|
399
401
|
|
|
400
402
|
struct OnTaskListItemPress {
|
|
@@ -1761,6 +1761,7 @@ struct EnrichedMarkdownMarkdownStyleMathStruct {
|
|
|
1761
1761
|
Float marginBottom{0.0};
|
|
1762
1762
|
std::string textAlign{};
|
|
1763
1763
|
std::string fontWeight{};
|
|
1764
|
+
Float glyphOverflow{0.0};
|
|
1764
1765
|
|
|
1765
1766
|
|
|
1766
1767
|
#ifdef RN_SERIALIZABLE_STATE
|
|
@@ -1776,6 +1777,7 @@ struct EnrichedMarkdownMarkdownStyleMathStruct {
|
|
|
1776
1777
|
result["marginBottom"] = marginBottom;
|
|
1777
1778
|
result["textAlign"] = textAlign;
|
|
1778
1779
|
result["fontWeight"] = fontWeight;
|
|
1780
|
+
result["glyphOverflow"] = glyphOverflow;
|
|
1779
1781
|
return result;
|
|
1780
1782
|
}
|
|
1781
1783
|
#endif
|
|
@@ -1816,6 +1818,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
|
|
|
1816
1818
|
if (tmp_fontWeight != map.end()) {
|
|
1817
1819
|
fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
|
|
1818
1820
|
}
|
|
1821
|
+
auto tmp_glyphOverflow = map.find("glyphOverflow");
|
|
1822
|
+
if (tmp_glyphOverflow != map.end()) {
|
|
1823
|
+
fromRawValue(context, tmp_glyphOverflow->second, result.glyphOverflow);
|
|
1824
|
+
}
|
|
1819
1825
|
}
|
|
1820
1826
|
|
|
1821
1827
|
static inline std::string toString(const EnrichedMarkdownMarkdownStyleMathStruct &value) {
|
|
@@ -1832,6 +1838,7 @@ struct EnrichedMarkdownMarkdownStyleInlineMathStruct {
|
|
|
1832
1838
|
SharedColor color{};
|
|
1833
1839
|
Float paddingVertical{0.0};
|
|
1834
1840
|
std::string fontWeight{};
|
|
1841
|
+
Float glyphOverflow{0.0};
|
|
1835
1842
|
|
|
1836
1843
|
|
|
1837
1844
|
#ifdef RN_SERIALIZABLE_STATE
|
|
@@ -1842,6 +1849,7 @@ struct EnrichedMarkdownMarkdownStyleInlineMathStruct {
|
|
|
1842
1849
|
result["color"] = ::facebook::react::toDynamic(color);
|
|
1843
1850
|
result["paddingVertical"] = paddingVertical;
|
|
1844
1851
|
result["fontWeight"] = fontWeight;
|
|
1852
|
+
result["glyphOverflow"] = glyphOverflow;
|
|
1845
1853
|
return result;
|
|
1846
1854
|
}
|
|
1847
1855
|
#endif
|
|
@@ -1862,6 +1870,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
|
|
|
1862
1870
|
if (tmp_fontWeight != map.end()) {
|
|
1863
1871
|
fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
|
|
1864
1872
|
}
|
|
1873
|
+
auto tmp_glyphOverflow = map.find("glyphOverflow");
|
|
1874
|
+
if (tmp_glyphOverflow != map.end()) {
|
|
1875
|
+
fromRawValue(context, tmp_glyphOverflow->second, result.glyphOverflow);
|
|
1876
|
+
}
|
|
1865
1877
|
}
|
|
1866
1878
|
|
|
1867
1879
|
static inline std::string toString(const EnrichedMarkdownMarkdownStyleInlineMathStruct &value) {
|
|
@@ -5807,6 +5819,7 @@ struct EnrichedMarkdownTextMarkdownStyleMathStruct {
|
|
|
5807
5819
|
Float marginBottom{0.0};
|
|
5808
5820
|
std::string textAlign{};
|
|
5809
5821
|
std::string fontWeight{};
|
|
5822
|
+
Float glyphOverflow{0.0};
|
|
5810
5823
|
|
|
5811
5824
|
|
|
5812
5825
|
#ifdef RN_SERIALIZABLE_STATE
|
|
@@ -5822,6 +5835,7 @@ struct EnrichedMarkdownTextMarkdownStyleMathStruct {
|
|
|
5822
5835
|
result["marginBottom"] = marginBottom;
|
|
5823
5836
|
result["textAlign"] = textAlign;
|
|
5824
5837
|
result["fontWeight"] = fontWeight;
|
|
5838
|
+
result["glyphOverflow"] = glyphOverflow;
|
|
5825
5839
|
return result;
|
|
5826
5840
|
}
|
|
5827
5841
|
#endif
|
|
@@ -5862,6 +5876,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
|
|
|
5862
5876
|
if (tmp_fontWeight != map.end()) {
|
|
5863
5877
|
fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
|
|
5864
5878
|
}
|
|
5879
|
+
auto tmp_glyphOverflow = map.find("glyphOverflow");
|
|
5880
|
+
if (tmp_glyphOverflow != map.end()) {
|
|
5881
|
+
fromRawValue(context, tmp_glyphOverflow->second, result.glyphOverflow);
|
|
5882
|
+
}
|
|
5865
5883
|
}
|
|
5866
5884
|
|
|
5867
5885
|
static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleMathStruct &value) {
|
|
@@ -5878,6 +5896,7 @@ struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct {
|
|
|
5878
5896
|
SharedColor color{};
|
|
5879
5897
|
Float paddingVertical{0.0};
|
|
5880
5898
|
std::string fontWeight{};
|
|
5899
|
+
Float glyphOverflow{0.0};
|
|
5881
5900
|
|
|
5882
5901
|
|
|
5883
5902
|
#ifdef RN_SERIALIZABLE_STATE
|
|
@@ -5888,6 +5907,7 @@ struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct {
|
|
|
5888
5907
|
result["color"] = ::facebook::react::toDynamic(color);
|
|
5889
5908
|
result["paddingVertical"] = paddingVertical;
|
|
5890
5909
|
result["fontWeight"] = fontWeight;
|
|
5910
|
+
result["glyphOverflow"] = glyphOverflow;
|
|
5891
5911
|
return result;
|
|
5892
5912
|
}
|
|
5893
5913
|
#endif
|
|
@@ -5908,6 +5928,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
|
|
|
5908
5928
|
if (tmp_fontWeight != map.end()) {
|
|
5909
5929
|
fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
|
|
5910
5930
|
}
|
|
5931
|
+
auto tmp_glyphOverflow = map.find("glyphOverflow");
|
|
5932
|
+
if (tmp_glyphOverflow != map.end()) {
|
|
5933
|
+
fromRawValue(context, tmp_glyphOverflow->second, result.glyphOverflow);
|
|
5934
|
+
}
|
|
5911
5935
|
}
|
|
5912
5936
|
|
|
5913
5937
|
static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct &value) {
|
|
@@ -144,8 +144,9 @@ template <typename StyleStruct> inline size_t computeStyleFingerprint(const Styl
|
|
|
144
144
|
hashTextLayout(s.table);
|
|
145
145
|
hashFields(s.table.headerFontFamily, s.table.cellPaddingHorizontal, s.table.cellPaddingVertical, s.table.borderWidth,
|
|
146
146
|
s.table.borderRadius, s.table.horizontalOverflow);
|
|
147
|
-
hashFields(s.math.fontSize, s.math.padding, s.math.marginTop, s.math.marginBottom, s.math.textAlign
|
|
148
|
-
|
|
147
|
+
hashFields(s.math.fontSize, s.math.padding, s.math.marginTop, s.math.marginBottom, s.math.textAlign,
|
|
148
|
+
s.math.glyphOverflow);
|
|
149
|
+
hashFields(s.inlineMath.paddingVertical, s.inlineMath.glyphOverflow);
|
|
149
150
|
hashFields(s.taskList.checkboxSize, s.taskList.checkboxBorderRadius);
|
|
150
151
|
|
|
151
152
|
return h;
|
|
@@ -42,23 +42,39 @@ public final class ENRMRaTeXRenderResult: NSObject {
|
|
|
42
42
|
/// Non-zero only in bold mode: half of it grows the glyph ink on each side.
|
|
43
43
|
private let boldStrokeWidth: CGFloat
|
|
44
44
|
private let boldStrokeColor: CGColor?
|
|
45
|
+
/// Headroom added above and below RaTeX's box. RaTeX sizes a formula by its TeX
|
|
46
|
+
/// metric box, which digit and capital outlines (and the bold stroke) overshoot;
|
|
47
|
+
/// every view and attachment clips to `totalHeight`, so that ink needs room inside it.
|
|
48
|
+
private let glyphOverflow: CGFloat
|
|
45
49
|
|
|
46
50
|
@objc public let width: CGFloat
|
|
47
51
|
@objc public let ascent: CGFloat
|
|
48
52
|
@objc public let descent: CGFloat
|
|
49
53
|
@objc public var totalHeight: CGFloat { ascent + descent }
|
|
50
54
|
|
|
51
|
-
init(renderer: RaTeXRenderer, boldStrokeWidth: CGFloat, boldStrokeColor: CGColor
|
|
55
|
+
init(renderer: RaTeXRenderer, boldStrokeWidth: CGFloat, boldStrokeColor: CGColor?, glyphOverflow: CGFloat) {
|
|
52
56
|
self.renderer = renderer
|
|
53
57
|
self.boldStrokeWidth = boldStrokeWidth
|
|
54
58
|
self.boldStrokeColor = boldStrokeColor
|
|
59
|
+
self.glyphOverflow = max(glyphOverflow, 0)
|
|
55
60
|
self.width = renderer.width
|
|
56
|
-
self.ascent = renderer.height
|
|
57
|
-
self.descent = renderer.depth
|
|
61
|
+
self.ascent = renderer.height + self.glyphOverflow
|
|
62
|
+
self.descent = renderer.depth + self.glyphOverflow
|
|
58
63
|
super.init()
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
@objc public func draw(in context: CGContext) {
|
|
67
|
+
guard glyphOverflow > 0 else {
|
|
68
|
+
drawFormula(in: context)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
context.saveGState()
|
|
72
|
+
context.translateBy(x: 0, y: glyphOverflow)
|
|
73
|
+
drawFormula(in: context)
|
|
74
|
+
context.restoreGState()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private func drawFormula(in context: CGContext) {
|
|
62
78
|
guard boldStrokeWidth > 0, let boldStrokeColor else {
|
|
63
79
|
renderer.draw(in: context)
|
|
64
80
|
return
|
|
@@ -90,7 +106,8 @@ public final class ENRMRaTeXBridge: NSObject {
|
|
|
90
106
|
displayMode: Bool,
|
|
91
107
|
fontSize: CGFloat,
|
|
92
108
|
color: UIColor,
|
|
93
|
-
bold: Bool
|
|
109
|
+
bold: Bool,
|
|
110
|
+
glyphOverflow: CGFloat
|
|
94
111
|
) -> ENRMRaTeXRenderResult? {
|
|
95
112
|
RaTeXFontLoader.ensureLoaded()
|
|
96
113
|
do {
|
|
@@ -100,7 +117,8 @@ public final class ENRMRaTeXBridge: NSObject {
|
|
|
100
117
|
return ENRMRaTeXRenderResult(
|
|
101
118
|
renderer: renderer,
|
|
102
119
|
boldStrokeWidth: strokeWidth,
|
|
103
|
-
boldStrokeColor: strokeWidth > 0 ? color.cgColor : nil
|
|
120
|
+
boldStrokeColor: strokeWidth > 0 ? color.cgColor : nil,
|
|
121
|
+
glyphOverflow: glyphOverflow
|
|
104
122
|
)
|
|
105
123
|
} catch {
|
|
106
124
|
NSLog("[RaTeX] Failed to parse LaTeX: %@", error.localizedDescription)
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
attachment.mathTextColor = [_config inlineMathColor];
|
|
31
31
|
attachment.containerPaddingVertical = [_config inlineMathPaddingVertical];
|
|
32
32
|
attachment.bold = ENRMMathFontWeightIsBold([_config inlineMathFontWeight]);
|
|
33
|
+
attachment.glyphOverflow = [_config inlineMathGlyphOverflow];
|
|
33
34
|
|
|
34
35
|
#if TARGET_OS_OSX
|
|
35
36
|
// On macOS, NSLayoutManager uses self.image/self.bounds rather than calling
|
package/ios/styles/StyleConfig.h
CHANGED
|
@@ -418,6 +418,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
418
418
|
- (void)setMathTextAlign:(NSString *)newValue;
|
|
419
419
|
- (NSString *)mathFontWeight;
|
|
420
420
|
- (void)setMathFontWeight:(NSString *)newValue;
|
|
421
|
+
- (CGFloat)mathGlyphOverflow;
|
|
422
|
+
- (void)setMathGlyphOverflow:(CGFloat)newValue;
|
|
421
423
|
|
|
422
424
|
// Inline Math properties
|
|
423
425
|
- (RCTUIColor *)inlineMathColor;
|
|
@@ -426,6 +428,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
426
428
|
- (void)setInlineMathPaddingVertical:(CGFloat)newValue;
|
|
427
429
|
- (NSString *)inlineMathFontWeight;
|
|
428
430
|
- (void)setInlineMathFontWeight:(NSString *)newValue;
|
|
431
|
+
- (CGFloat)inlineMathGlyphOverflow;
|
|
432
|
+
- (void)setInlineMathGlyphOverflow:(CGFloat)newValue;
|
|
429
433
|
// Spoiler properties
|
|
430
434
|
- (RCTUIColor *)spoilerColor;
|
|
431
435
|
- (void)setSpoilerColor:(RCTUIColor *)newValue;
|
|
@@ -244,10 +244,12 @@ static inline NSString *normalizedFontWeight(NSString *fontWeight)
|
|
|
244
244
|
CGFloat _mathMarginBottom;
|
|
245
245
|
NSString *_mathTextAlign;
|
|
246
246
|
NSString *_mathFontWeight;
|
|
247
|
+
CGFloat _mathGlyphOverflow;
|
|
247
248
|
// Inline Math properties
|
|
248
249
|
RCTUIColor *_inlineMathColor;
|
|
249
250
|
CGFloat _inlineMathPaddingVertical;
|
|
250
251
|
NSString *_inlineMathFontWeight;
|
|
252
|
+
CGFloat _inlineMathGlyphOverflow;
|
|
251
253
|
// Spoiler properties
|
|
252
254
|
RCTUIColor *_spoilerColor;
|
|
253
255
|
CGFloat _spoilerParticleDensity;
|
|
@@ -522,9 +524,11 @@ static inline NSString *normalizedFontWeight(NSString *fontWeight)
|
|
|
522
524
|
copy->_mathMarginBottom = _mathMarginBottom;
|
|
523
525
|
copy->_mathTextAlign = [_mathTextAlign copy];
|
|
524
526
|
copy->_mathFontWeight = [_mathFontWeight copy];
|
|
527
|
+
copy->_mathGlyphOverflow = _mathGlyphOverflow;
|
|
525
528
|
copy->_inlineMathColor = [_inlineMathColor copy];
|
|
526
529
|
copy->_inlineMathPaddingVertical = _inlineMathPaddingVertical;
|
|
527
530
|
copy->_inlineMathFontWeight = [_inlineMathFontWeight copy];
|
|
531
|
+
copy->_inlineMathGlyphOverflow = _inlineMathGlyphOverflow;
|
|
528
532
|
copy->_spoilerColor = [_spoilerColor copy];
|
|
529
533
|
copy->_spoilerParticleDensity = _spoilerParticleDensity;
|
|
530
534
|
copy->_spoilerParticleSpeed = _spoilerParticleSpeed;
|
|
@@ -2658,6 +2662,26 @@ static const CGFloat kDefaultMinGap = 4.0;
|
|
|
2658
2662
|
_inlineMathPaddingVertical = newValue;
|
|
2659
2663
|
}
|
|
2660
2664
|
|
|
2665
|
+
- (CGFloat)mathGlyphOverflow
|
|
2666
|
+
{
|
|
2667
|
+
return _mathGlyphOverflow;
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
- (void)setMathGlyphOverflow:(CGFloat)newValue
|
|
2671
|
+
{
|
|
2672
|
+
_mathGlyphOverflow = newValue;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
- (CGFloat)inlineMathGlyphOverflow
|
|
2676
|
+
{
|
|
2677
|
+
return _inlineMathGlyphOverflow;
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
- (void)setInlineMathGlyphOverflow:(CGFloat)newValue
|
|
2681
|
+
{
|
|
2682
|
+
_inlineMathGlyphOverflow = newValue;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2661
2685
|
// ── Spoiler ─────────────────────────────────────────────────────────────
|
|
2662
2686
|
|
|
2663
2687
|
- (RCTUIColor *)spoilerColor
|
package/ios/utils/ENRMLinkChip.m
CHANGED
|
@@ -155,7 +155,8 @@ void ENRMEnumerateLinkChipFragments(NSLayoutManager *layoutManager, NSTextContai
|
|
|
155
155
|
|
|
156
156
|
CGFloat right;
|
|
157
157
|
if (visibleGlyphEnd < lineEnd) {
|
|
158
|
-
right =
|
|
158
|
+
right =
|
|
159
|
+
lineRect.origin.x + [layoutManager locationForGlyphAtIndex:visibleGlyphEnd].x;
|
|
159
160
|
} else {
|
|
160
161
|
right = CGRectGetMaxX(usedRect);
|
|
161
162
|
}
|
|
@@ -14,6 +14,7 @@ extern NSString *const ENRMSelectionWholeKey;
|
|
|
14
14
|
extern NSString *const ENRMSelectionRectKey;
|
|
15
15
|
extern NSString *const ENRMSelectionStartRectKey;
|
|
16
16
|
extern NSString *const ENRMSelectionEndRectKey;
|
|
17
|
+
extern NSString *const ENRMSelectionAdjustingKey;
|
|
17
18
|
/// Only in `ENRMTextSelectionInTextView` results: whether the range spans the
|
|
18
19
|
/// whole text (same threshold `markdownForRange` uses for the cached markdown).
|
|
19
20
|
extern NSString *const ENRMSelectionFullKey;
|
|
@@ -63,6 +64,28 @@ NSDictionary *_Nullable ENRMTextSelectionInTextView(UITextView *textView, UIView
|
|
|
63
64
|
|
|
64
65
|
@end
|
|
65
66
|
|
|
67
|
+
#if !TARGET_OS_OSX
|
|
68
|
+
/// Tells when the user is dragging a selection handle (or holding the loupe).
|
|
69
|
+
/// `UITextView` doesn't call `textViewDidChangeSelection:` during the drag, so
|
|
70
|
+
/// this watches the text view's own selection gestures: every recognizer of
|
|
71
|
+
/// the view and its subviews except scroll, pinch and taps. UIKit adds the
|
|
72
|
+
/// handle recognizers lazily, so call `trackTextView:` again on each selection
|
|
73
|
+
/// change. `change` runs whenever `adjusting` flips.
|
|
74
|
+
@interface ENRMSelectionGestureTracker : NSObject
|
|
75
|
+
|
|
76
|
+
- (instancetype)initWithChange:(void (^)(void))change NS_DESIGNATED_INITIALIZER;
|
|
77
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
78
|
+
|
|
79
|
+
/// A tracked gesture is in `Began` / `Changed`.
|
|
80
|
+
@property (nonatomic, readonly) BOOL adjusting;
|
|
81
|
+
|
|
82
|
+
- (void)trackTextView:(UITextView *)textView;
|
|
83
|
+
/// Clears `adjusting` without calling `change` (view recycling).
|
|
84
|
+
- (void)reset;
|
|
85
|
+
|
|
86
|
+
@end
|
|
87
|
+
#endif
|
|
88
|
+
|
|
66
89
|
#ifdef __cplusplus
|
|
67
90
|
/// Converts a payload into a codegen `OnSelectionChange` struct. Templated
|
|
68
91
|
/// because each component has its own (structurally identical) event struct.
|
|
@@ -74,6 +97,7 @@ template <typename Event> inline Event ENRMSelectionChangeEventFromPayload(NSDic
|
|
|
74
97
|
event.text = std::string([payload[ENRMSelectionTextKey] UTF8String] ?: "");
|
|
75
98
|
event.markdown = std::string([payload[ENRMSelectionMarkdownKey] UTF8String] ?: "");
|
|
76
99
|
event.whole = [payload[ENRMSelectionWholeKey] boolValue];
|
|
100
|
+
event.adjusting = [payload[ENRMSelectionAdjustingKey] boolValue];
|
|
77
101
|
|
|
78
102
|
auto assign = [](auto &target, NSValue *value) {
|
|
79
103
|
#if TARGET_OS_OSX
|
|
@@ -9,6 +9,7 @@ NSString *const ENRMSelectionWholeKey = @"whole";
|
|
|
9
9
|
NSString *const ENRMSelectionRectKey = @"rect";
|
|
10
10
|
NSString *const ENRMSelectionStartRectKey = @"startRect";
|
|
11
11
|
NSString *const ENRMSelectionEndRectKey = @"endRect";
|
|
12
|
+
NSString *const ENRMSelectionAdjustingKey = @"adjusting";
|
|
12
13
|
NSString *const ENRMSelectionFullKey = @"full";
|
|
13
14
|
|
|
14
15
|
static NSValue *ENRMRectValue(CGRect rect)
|
|
@@ -202,3 +203,80 @@ NSDictionary *ENRMTextSelectionInTextView(UITextView *textView, UIView *targetVi
|
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
@end
|
|
206
|
+
|
|
207
|
+
#if !TARGET_OS_OSX
|
|
208
|
+
static void ENRMCollectGestures(UIView *view, NSMutableArray<UIGestureRecognizer *> *into)
|
|
209
|
+
{
|
|
210
|
+
for (UIGestureRecognizer *recognizer in view.gestureRecognizers) {
|
|
211
|
+
[into addObject:recognizer];
|
|
212
|
+
}
|
|
213
|
+
for (UIView *subview in view.subviews) {
|
|
214
|
+
ENRMCollectGestures(subview, into);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@implementation ENRMSelectionGestureTracker {
|
|
219
|
+
void (^_change)(void);
|
|
220
|
+
NSHashTable<UIGestureRecognizer *> *_gestures;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
- (instancetype)initWithChange:(void (^)(void))change
|
|
224
|
+
{
|
|
225
|
+
if (self = [super init]) {
|
|
226
|
+
_change = [change copy];
|
|
227
|
+
_gestures = [NSHashTable weakObjectsHashTable];
|
|
228
|
+
}
|
|
229
|
+
return self;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
- (void)dealloc
|
|
233
|
+
{
|
|
234
|
+
// Recognizers don't retain their targets.
|
|
235
|
+
for (UIGestureRecognizer *recognizer in _gestures) {
|
|
236
|
+
[recognizer removeTarget:self action:@selector(gestureChanged:)];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
- (void)trackTextView:(UITextView *)textView
|
|
241
|
+
{
|
|
242
|
+
NSMutableArray<UIGestureRecognizer *> *all = [NSMutableArray array];
|
|
243
|
+
ENRMCollectGestures(textView, all);
|
|
244
|
+
for (UIGestureRecognizer *recognizer in all) {
|
|
245
|
+
if ([_gestures containsObject:recognizer]) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (recognizer == textView.panGestureRecognizer || recognizer == textView.pinchGestureRecognizer) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
[_gestures addObject:recognizer];
|
|
255
|
+
[recognizer addTarget:self action:@selector(gestureChanged:)];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
- (void)reset
|
|
260
|
+
{
|
|
261
|
+
_adjusting = NO;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
- (void)gestureChanged:(UIGestureRecognizer *)recognizer
|
|
265
|
+
{
|
|
266
|
+
BOOL adjusting = NO;
|
|
267
|
+
for (UIGestureRecognizer *tracked in _gestures) {
|
|
268
|
+
UIGestureRecognizerState state = tracked.state;
|
|
269
|
+
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged) {
|
|
270
|
+
adjusting = YES;
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (adjusting == _adjusting) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
_adjusting = adjusting;
|
|
278
|
+
_change();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
@end
|
|
282
|
+
#endif
|
|
@@ -1167,6 +1167,11 @@ BOOL applyMarkdownStyleToConfig(StyleConfig *config, const MarkdownStyle &newSty
|
|
|
1167
1167
|
changed = YES;
|
|
1168
1168
|
}
|
|
1169
1169
|
|
|
1170
|
+
if (newStyle.math.glyphOverflow != oldStyle.math.glyphOverflow) {
|
|
1171
|
+
[config setMathGlyphOverflow:newStyle.math.glyphOverflow];
|
|
1172
|
+
changed = YES;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1170
1175
|
if (newStyle.math.marginTop != oldStyle.math.marginTop) {
|
|
1171
1176
|
[config setMathMarginTop:newStyle.math.marginTop];
|
|
1172
1177
|
changed = YES;
|
|
@@ -1215,6 +1220,11 @@ BOOL applyMarkdownStyleToConfig(StyleConfig *config, const MarkdownStyle &newSty
|
|
|
1215
1220
|
changed = YES;
|
|
1216
1221
|
}
|
|
1217
1222
|
|
|
1223
|
+
if (newStyle.inlineMath.glyphOverflow != oldStyle.inlineMath.glyphOverflow) {
|
|
1224
|
+
[config setInlineMathGlyphOverflow:newStyle.inlineMath.glyphOverflow];
|
|
1225
|
+
changed = YES;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1218
1228
|
// ── Spoiler ─────────────────────────────────────────────────────────────
|
|
1219
1229
|
|
|
1220
1230
|
if (newStyle.spoiler.color != oldStyle.spoiler.color) {
|
|
@@ -104,7 +104,8 @@
|
|
|
104
104
|
displayMode:YES
|
|
105
105
|
fontSize:config.mathFontSize
|
|
106
106
|
color:config.mathColor
|
|
107
|
-
bold:ENRMMathFontWeightIsBold(config.mathFontWeight)
|
|
107
|
+
bold:ENRMMathFontWeightIsBold(config.mathFontWeight)
|
|
108
|
+
glyphOverflow:config.mathGlyphOverflow];
|
|
108
109
|
_mathView.renderResult = result;
|
|
109
110
|
_mathView.fallbackSource = result ? nil : ENRMMathFallbackString(latex, @"$$", config.mathFontSize, config.mathColor);
|
|
110
111
|
|
|
@@ -199,7 +200,8 @@
|
|
|
199
200
|
displayMode:YES
|
|
200
201
|
fontSize:config.mathFontSize
|
|
201
202
|
color:config.mathColor
|
|
202
|
-
bold:ENRMMathFontWeightIsBold(config.mathFontWeight)
|
|
203
|
+
bold:ENRMMathFontWeightIsBold(config.mathFontWeight)
|
|
204
|
+
glyphOverflow:config.mathGlyphOverflow];
|
|
203
205
|
if (result) {
|
|
204
206
|
return ceil(result.totalHeight) + padding * 2;
|
|
205
207
|
}
|
|
@@ -181,12 +181,14 @@ interface MathStyleInternal {
|
|
|
181
181
|
marginBottom: CodegenTypes.Float;
|
|
182
182
|
textAlign: string;
|
|
183
183
|
fontWeight: string;
|
|
184
|
+
glyphOverflow: CodegenTypes.Float;
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
interface InlineMathStyleInternal {
|
|
187
188
|
color: ColorValue;
|
|
188
189
|
paddingVertical: CodegenTypes.Float;
|
|
189
190
|
fontWeight: string;
|
|
191
|
+
glyphOverflow: CodegenTypes.Float;
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
interface SpoilerParticlesStyleInternal {
|
|
@@ -308,6 +310,7 @@ export interface SelectionChangeEvent {
|
|
|
308
310
|
width: CodegenTypes.Double;
|
|
309
311
|
height: CodegenTypes.Double;
|
|
310
312
|
};
|
|
313
|
+
adjusting: boolean;
|
|
311
314
|
}
|
|
312
315
|
|
|
313
316
|
export interface TaskListItemPressEvent {
|
|
@@ -182,12 +182,14 @@ interface MathStyleInternal {
|
|
|
182
182
|
marginBottom: CodegenTypes.Float;
|
|
183
183
|
textAlign: string;
|
|
184
184
|
fontWeight: string;
|
|
185
|
+
glyphOverflow: CodegenTypes.Float;
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
interface InlineMathStyleInternal {
|
|
188
189
|
color: ColorValue;
|
|
189
190
|
paddingVertical: CodegenTypes.Float;
|
|
190
191
|
fontWeight: string;
|
|
192
|
+
glyphOverflow: CodegenTypes.Float;
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
interface SpoilerParticlesStyleInternal {
|
|
@@ -309,6 +311,7 @@ export interface SelectionChangeEvent {
|
|
|
309
311
|
width: CodegenTypes.Double;
|
|
310
312
|
height: CodegenTypes.Double;
|
|
311
313
|
};
|
|
314
|
+
adjusting: boolean;
|
|
312
315
|
}
|
|
313
316
|
|
|
314
317
|
export interface TaskListItemPressEvent {
|
|
@@ -284,12 +284,14 @@ const DEFAULT_NORMALIZED_STYLE = Object.freeze({
|
|
|
284
284
|
marginTop: 0,
|
|
285
285
|
marginBottom: 16,
|
|
286
286
|
textAlign: 'center',
|
|
287
|
-
fontWeight: 'normal'
|
|
287
|
+
fontWeight: 'normal',
|
|
288
|
+
glyphOverflow: 0
|
|
288
289
|
},
|
|
289
290
|
inlineMath: {
|
|
290
291
|
color: defaultTextColor,
|
|
291
292
|
paddingVertical: 4,
|
|
292
|
-
fontWeight: 'normal'
|
|
293
|
+
fontWeight: 'normal',
|
|
294
|
+
glyphOverflow: 0
|
|
293
295
|
},
|
|
294
296
|
taskList: {
|
|
295
297
|
checkedColor: Platform.select({
|