react-native-enriched-markdown-scaffold 0.7.4-scaffold.1 → 0.7.4-scaffold.11
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/build.gradle +5 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +9 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +3 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +10 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +7 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +10 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +50 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +6 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +38 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +174 -9
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockSyntaxSentinel.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +71 -12
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +8 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputLayoutManager.kt +30 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +7 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +5 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathFontWeight.kt +25 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +12 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +7 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/SpannableExtensions.kt +12 -4
- 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 +2 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlinePlaceholderSpan.kt +7 -3
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +8 -5
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathTypeface.kt +30 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +3 -1
- package/docs/API_REFERENCE.md +43 -0
- package/docs/INPUT.md +87 -0
- package/docs/LATEX_MATH.md +62 -0
- package/docs/STYLES.md +3 -0
- package/ios/EnrichedMarkdown.mm +44 -12
- package/ios/EnrichedMarkdownText.mm +47 -11
- package/ios/attachments/ENRMMathInlineAttachment+macOS.m +5 -1
- package/ios/attachments/ENRMMathInlineAttachment.h +3 -0
- package/ios/attachments/ENRMMathInlineAttachment.m +2 -1
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +10 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +7 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +10 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +50 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +29 -0
- package/ios/input/ENRMBlockSyntaxSentinel.h +25 -0
- package/ios/input/ENRMBlockSyntaxSentinel.mm +80 -0
- package/ios/input/ENRMInputFormatter.h +4 -0
- package/ios/input/ENRMInputFormatter.mm +2 -0
- package/ios/input/ENRMInputParser.h +5 -0
- package/ios/input/ENRMInputParser.mm +79 -6
- package/ios/input/ENRMInputTextView.mm +11 -1
- package/ios/input/EnrichedMarkdownTextInput.h +5 -0
- package/ios/input/EnrichedMarkdownTextInput.mm +88 -22
- package/ios/input/InputStylePropsUtils.h +13 -0
- package/ios/internals/MeasurementCache.h +1 -0
- package/ios/math/ENRMRaTeXBridge.swift +52 -3
- package/ios/parser/ENRMMarkdownParser.h +8 -0
- package/ios/parser/ENRMMarkdownParser.mm +11 -0
- package/ios/renderer/ENRMMathInlineRenderer.m +3 -0
- package/ios/renderer/ListItemRenderer.m +8 -5
- package/ios/styles/StyleConfig.h +6 -0
- package/ios/styles/StyleConfig.mm +36 -0
- package/ios/utils/ENRMMathFontWeight.h +18 -0
- package/ios/utils/StylePropsUtils.h +21 -0
- package/ios/views/ENRMMathContainerView.m +3 -1
- package/lib/module/EnrichedMarkdownNativeComponent.ts +3 -0
- package/lib/module/EnrichedMarkdownTextInput.js +17 -0
- package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
- package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +34 -0
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.js +5 -2
- package/lib/module/normalizeMarkdownStyle.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.web.js +5 -2
- package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
- package/lib/module/normalizeMarkdownTextInputStyle.js +7 -3
- package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
- package/lib/module/web/globalStyles.js +8 -1
- package/lib/module/web/globalStyles.js.map +1 -1
- package/lib/module/web/styles.js +3 -1
- package/lib/module/web/styles.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/EnrichedMarkdownTextInput.d.ts +26 -1
- package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +28 -0
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.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/index.d.ts +1 -1
- package/lib/typescript/src/index.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/normalizeMarkdownTextInputStyle.d.ts +1 -0
- package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyle.d.ts +32 -0
- package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +3 -0
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +15 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/lib/typescript/src/web/styles.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/EnrichedMarkdownNativeComponent.ts +3 -0
- package/src/EnrichedMarkdownTextInput.tsx +41 -0
- package/src/EnrichedMarkdownTextInputNativeComponent.ts +34 -0
- package/src/EnrichedMarkdownTextNativeComponent.ts +3 -0
- package/src/index.tsx +1 -0
- package/src/normalizeMarkdownStyle.ts +6 -1
- package/src/normalizeMarkdownStyle.web.ts +6 -1
- package/src/normalizeMarkdownTextInputStyle.ts +5 -0
- package/src/types/MarkdownStyle.ts +32 -0
- package/src/types/MarkdownStyleInternal.ts +3 -0
- package/src/types/events.ts +16 -0
- package/src/web/globalStyles.ts +7 -0
- package/src/web/styles.ts +5 -1
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
copy.mathPaddingVertical = _mathPaddingVertical;
|
|
57
57
|
copy.mathSelectedBackgroundColor = _mathSelectedBackgroundColor;
|
|
58
58
|
copy.mathSelectedBorderColor = _mathSelectedBorderColor;
|
|
59
|
+
copy.mathFontWeight = _mathFontWeight;
|
|
59
60
|
copy.mathBlockColor = _mathBlockColor;
|
|
60
61
|
copy.mathBlockFontSize = _mathBlockFontSize;
|
|
61
62
|
copy.mathBlockBackgroundColor = _mathBlockBackgroundColor;
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
copy.mathBlockMarginTop = _mathBlockMarginTop;
|
|
70
71
|
copy.mathBlockMarginBottom = _mathBlockMarginBottom;
|
|
71
72
|
copy.mathBlockAlignment = _mathBlockAlignment;
|
|
73
|
+
copy.mathBlockFontWeight = _mathBlockFontWeight;
|
|
72
74
|
return copy;
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -22,6 +22,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
22
22
|
|
|
23
23
|
- (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown;
|
|
24
24
|
|
|
25
|
+
/// `blockSyntax = NO` hides block structure from md4c (see ENRMBlockSyntaxSentinel)
|
|
26
|
+
/// and skips `ENRMInputRemendComplete`, so list markers, headings and blockquotes
|
|
27
|
+
/// survive as text and the markdown round-trips byte-for-byte.
|
|
28
|
+
- (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown blockSyntax:(BOOL)blockSyntax;
|
|
29
|
+
|
|
25
30
|
@end
|
|
26
31
|
|
|
27
32
|
NS_ASSUME_NONNULL_END
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#import "ENRMInputParser.h"
|
|
2
|
+
#import "ENRMBlockSyntaxSentinel.h"
|
|
2
3
|
#import "ENRMFormattingRange.h"
|
|
3
4
|
#import "ENRMInputRemend.h"
|
|
4
5
|
#include "md4c.h"
|
|
@@ -14,6 +15,11 @@
|
|
|
14
15
|
@implementation ENRMParseResult
|
|
15
16
|
@end
|
|
16
17
|
|
|
18
|
+
@interface ENRMInputParser ()
|
|
19
|
+
/// Shared body of both public entry points. `remend` gates `ENRMInputRemendComplete`.
|
|
20
|
+
- (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown remend:(BOOL)remend;
|
|
21
|
+
@end
|
|
22
|
+
|
|
17
23
|
@implementation ENRMMathAtom
|
|
18
24
|
@end
|
|
19
25
|
|
|
@@ -256,9 +262,9 @@ static int onText(MD_TEXTTYPE textType, const MD_CHAR *text, MD_SIZE size, void
|
|
|
256
262
|
return 0;
|
|
257
263
|
}
|
|
258
264
|
|
|
259
|
-
static bool runMd4cParse(NSString *markdown, ParseContext &context)
|
|
265
|
+
static bool runMd4cParse(NSString *markdown, ParseContext &context, bool remend)
|
|
260
266
|
{
|
|
261
|
-
NSString *completed = ENRMInputRemendComplete(markdown);
|
|
267
|
+
NSString *completed = remend ? ENRMInputRemendComplete(markdown) : markdown;
|
|
262
268
|
const char *completedUTF8 = [completed UTF8String];
|
|
263
269
|
size_t completedLength = strlen(completedUTF8);
|
|
264
270
|
size_t originalLength = [markdown lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
|
@@ -286,14 +292,14 @@ struct ParsedSpans {
|
|
|
286
292
|
std::vector<MathSpanInfo> mathSpans;
|
|
287
293
|
};
|
|
288
294
|
|
|
289
|
-
static NSArray<ENRMInputStyledRange *> *runParseInternal(NSString *markdown, ParsedSpans &out)
|
|
295
|
+
static NSArray<ENRMInputStyledRange *> *runParseInternal(NSString *markdown, ParsedSpans &out, bool remend)
|
|
290
296
|
{
|
|
291
297
|
if (markdown.length == 0) {
|
|
292
298
|
return @[];
|
|
293
299
|
}
|
|
294
300
|
|
|
295
301
|
ParseContext context;
|
|
296
|
-
if (!runMd4cParse(markdown, context)) {
|
|
302
|
+
if (!runMd4cParse(markdown, context, remend)) {
|
|
297
303
|
return @[];
|
|
298
304
|
}
|
|
299
305
|
|
|
@@ -355,10 +361,77 @@ static NSArray<ENRMInputStyledRange *> *runParseInternal(NSString *markdown, Par
|
|
|
355
361
|
- (NSArray<ENRMInputStyledRange *> *)parse:(NSString *)markdown
|
|
356
362
|
{
|
|
357
363
|
ParsedSpans spans;
|
|
358
|
-
return runParseInternal(markdown, spans);
|
|
364
|
+
return runParseInternal(markdown, spans, /* remend */ true);
|
|
359
365
|
}
|
|
360
366
|
|
|
361
367
|
- (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown
|
|
368
|
+
{
|
|
369
|
+
return [self parseToPlainTextAndRanges:markdown remend:YES];
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
- (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown blockSyntax:(BOOL)blockSyntax
|
|
373
|
+
{
|
|
374
|
+
if (blockSyntax) {
|
|
375
|
+
return [self parseToPlainTextAndRanges:markdown];
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
NSString *canonical = ENRMBlockSyntaxCanonicalize(markdown);
|
|
379
|
+
if (canonical.length == 0) {
|
|
380
|
+
ENRMParseResult *empty = [[ENRMParseResult alloc] init];
|
|
381
|
+
empty.plainText = @"";
|
|
382
|
+
empty.formattingRanges = @[];
|
|
383
|
+
empty.mathAtoms = @[];
|
|
384
|
+
return empty;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Remending is skipped too: its speculative closing delimiters are the other
|
|
388
|
+
// source of characters the serializer cannot replay.
|
|
389
|
+
ENRMParseResult *encoded = [self parseToPlainTextAndRanges:ENRMBlockSyntaxEncode(canonical) remend:NO];
|
|
390
|
+
|
|
391
|
+
NSString *decoded = ENRMBlockSyntaxDecode(encoded.plainText);
|
|
392
|
+
ENRMParseResult *result = [[ENRMParseResult alloc] init];
|
|
393
|
+
|
|
394
|
+
if (decoded == nil) {
|
|
395
|
+
result.plainText = canonical;
|
|
396
|
+
result.formattingRanges = @[];
|
|
397
|
+
result.mathAtoms = @[];
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Only the leading sentinel was removed, so every offset shifts by exactly one.
|
|
402
|
+
NSUInteger decodedLength = decoded.length;
|
|
403
|
+
|
|
404
|
+
NSMutableArray<ENRMFormattingRange *> *shiftedRanges =
|
|
405
|
+
[NSMutableArray arrayWithCapacity:encoded.formattingRanges.count];
|
|
406
|
+
for (ENRMFormattingRange *range in encoded.formattingRanges) {
|
|
407
|
+
NSRange r = range.range;
|
|
408
|
+
if (r.location == 0 || r.length == 0 || NSMaxRange(r) - 1 > decodedLength) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
[shiftedRanges addObject:[ENRMFormattingRange rangeWithType:range.type
|
|
412
|
+
range:NSMakeRange(r.location - 1, r.length)
|
|
413
|
+
url:range.url]];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
NSMutableArray<ENRMMathAtom *> *shiftedAtoms = [NSMutableArray arrayWithCapacity:encoded.mathAtoms.count];
|
|
417
|
+
for (ENRMMathAtom *atom in encoded.mathAtoms) {
|
|
418
|
+
if (atom.position == 0 || atom.position - 1 >= decodedLength) {
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
ENRMMathAtom *shifted = [[ENRMMathAtom alloc] init];
|
|
422
|
+
shifted.position = atom.position - 1;
|
|
423
|
+
shifted.latex = atom.latex;
|
|
424
|
+
shifted.displayMode = atom.displayMode;
|
|
425
|
+
[shiftedAtoms addObject:shifted];
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
result.plainText = decoded;
|
|
429
|
+
result.formattingRanges = shiftedRanges;
|
|
430
|
+
result.mathAtoms = shiftedAtoms;
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
- (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown remend:(BOOL)remend
|
|
362
435
|
{
|
|
363
436
|
ENRMParseResult *parseResult = [[ENRMParseResult alloc] init];
|
|
364
437
|
|
|
@@ -370,7 +443,7 @@ static NSArray<ENRMInputStyledRange *> *runParseInternal(NSString *markdown, Par
|
|
|
370
443
|
}
|
|
371
444
|
|
|
372
445
|
ParsedSpans parsedSpans;
|
|
373
|
-
NSArray<ENRMInputStyledRange *> *styledRanges = runParseInternal(markdown, parsedSpans);
|
|
446
|
+
NSArray<ENRMInputStyledRange *> *styledRanges = runParseInternal(markdown, parsedSpans, remend);
|
|
374
447
|
|
|
375
448
|
// Compute byte map + raw byte ranges for math spans so we can strip the
|
|
376
449
|
// entire `$...$` (or `$$...$$`) syntax and inject a single `` at each.
|
|
@@ -46,12 +46,22 @@ NSString *const kENRMMarkdownPasteboardType = @"com.swmansion.enriched-markdown.
|
|
|
46
46
|
markdown = [[NSString alloc] initWithData:markdownValue encoding:NSUTF8StringEncoding];
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
NSString *plainText = pasteboard.string;
|
|
50
|
+
|
|
51
|
+
// Both flavors are read before anything is decided, then nothing is written:
|
|
52
|
+
// JS owns the paste from here and must call resolvePaste. Mutating the buffer
|
|
53
|
+
// first would mean a handler that dies mid-flight leaves the selection gone
|
|
54
|
+
// with no text to show for it — a no-op paste is the visible failure.
|
|
55
|
+
if (self.markdownTextInput.interceptPaste && (plainText.length > 0 || markdown.length > 0)) {
|
|
56
|
+
[self.markdownTextInput emitOnPasteWithText:(plainText ?: @"") markdown:(markdown ?: @"")];
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
if (markdown.length > 0 && self.markdownTextInput != nil) {
|
|
50
61
|
[self.markdownTextInput pasteMarkdown:markdown];
|
|
51
62
|
return;
|
|
52
63
|
}
|
|
53
64
|
|
|
54
|
-
NSString *plainText = pasteboard.string;
|
|
55
65
|
if (plainText.length > 0) {
|
|
56
66
|
[self replaceRange:self.selectedTextRange withText:plainText];
|
|
57
67
|
}
|
|
@@ -8,12 +8,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
8
8
|
|
|
9
9
|
@interface EnrichedMarkdownTextInput : RCTViewComponentView
|
|
10
10
|
@property (nonatomic, assign) BOOL blockEmitting;
|
|
11
|
+
@property (nonatomic, assign) BOOL interceptPaste;
|
|
11
12
|
- (CGSize)measureSize:(CGFloat)maxWidth;
|
|
12
13
|
- (nullable NSString *)markdownForSelectedRange;
|
|
13
14
|
- (void)copyToClipboard;
|
|
14
15
|
- (void)pasteMarkdown:(NSString *)markdown;
|
|
15
16
|
- (void)replaceSelectedTextWith:(NSString *)text formattingRanges:(NSArray *)ranges;
|
|
16
17
|
- (void)scheduleRelayoutIfNeeded;
|
|
18
|
+
// Paste interception. Declared here rather than in +Internal.h because
|
|
19
|
+
// ENRMInputTextView.mm only imports that header on macOS.
|
|
20
|
+
- (void)emitOnPasteWithText:(NSString *)text markdown:(NSString *)markdown;
|
|
21
|
+
- (void)resolvePaste:(NSString *)text markdown:(NSString *)markdown;
|
|
17
22
|
@end
|
|
18
23
|
|
|
19
24
|
NS_ASSUME_NONNULL_END
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#import "ENRMInputTextView.h"
|
|
14
14
|
#import "ENRMLinkRegexConfig.h"
|
|
15
15
|
#import "ENRMMarkdownSerializer.h"
|
|
16
|
+
#import "ENRMMathFontWeight.h"
|
|
16
17
|
#if ENRICHED_MARKDOWN_MATH
|
|
17
18
|
#import "ENRMMathInlineAttachment.h"
|
|
18
19
|
#endif
|
|
@@ -68,6 +69,8 @@ using namespace facebook::react;
|
|
|
68
69
|
BOOL _isApplyingFormatting;
|
|
69
70
|
BOOL _isTextChanging;
|
|
70
71
|
BOOL _emitMarkdown;
|
|
72
|
+
BOOL _blockSyntax;
|
|
73
|
+
NSString *_lastImportedMarkdown;
|
|
71
74
|
CFTimeInterval _lastTextChangeTime;
|
|
72
75
|
|
|
73
76
|
ENRMPlaceholderLabel *_placeholderLabel;
|
|
@@ -142,6 +145,8 @@ using namespace facebook::react;
|
|
|
142
145
|
|
|
143
146
|
self.backgroundColor = [RCTUIColor clearColor];
|
|
144
147
|
_blockEmitting = NO;
|
|
148
|
+
_blockSyntax = YES;
|
|
149
|
+
_lastImportedMarkdown = nil;
|
|
145
150
|
_heightUpdateCounter = 0;
|
|
146
151
|
_formatter = [[ENRMInputFormatter alloc] init];
|
|
147
152
|
_formatterStyle = [[ENRMInputFormatterStyle alloc] init];
|
|
@@ -253,6 +258,20 @@ using namespace facebook::react;
|
|
|
253
258
|
|
|
254
259
|
#if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
|
|
255
260
|
|
|
261
|
+
// Glyph rect of the chip at `index`, in _textView coordinates (the same space
|
|
262
|
+
// `locationInView:_textView` reports). Single source of truth for both the tap
|
|
263
|
+
// hit-test and the rect reported to JS.
|
|
264
|
+
- (CGRect)mathChipRectInTextViewAtIndex:(NSUInteger)index layoutManager:(NSLayoutManager *)lm
|
|
265
|
+
{
|
|
266
|
+
if (lm == nil)
|
|
267
|
+
return CGRectNull;
|
|
268
|
+
NSRange glyphRange = [lm glyphRangeForCharacterRange:NSMakeRange(index, 1) actualCharacterRange:NULL];
|
|
269
|
+
CGRect rect = [lm boundingRectForGlyphRange:glyphRange inTextContainer:_textView.textContainer];
|
|
270
|
+
rect.origin.x += _textView.textContainerInset.left;
|
|
271
|
+
rect.origin.y += _textView.textContainerInset.top;
|
|
272
|
+
return rect;
|
|
273
|
+
}
|
|
274
|
+
|
|
256
275
|
- (void)handleTapForMathChip:(UITapGestureRecognizer *)gesture
|
|
257
276
|
{
|
|
258
277
|
if (gesture.state != UIGestureRecognizerStateRecognized)
|
|
@@ -265,23 +284,28 @@ using namespace facebook::react;
|
|
|
265
284
|
if (idx < 0)
|
|
266
285
|
return;
|
|
267
286
|
NSTextStorage *storage = _textView.textStorage;
|
|
268
|
-
|
|
287
|
+
NSLayoutManager *lm = storage.layoutManagers.firstObject;
|
|
288
|
+
// The closest position can land just past the chip, so probe both `idx` and `idx-1`.
|
|
289
|
+
// `closestPositionToPoint:` has no distance bound — it clamps a tap anywhere in the
|
|
290
|
+
// text view (blank space past the text, textContainerInset padding) onto the nearest
|
|
291
|
+
// character. Requiring the touch to fall inside the chip's own glyph rect is what
|
|
292
|
+
// keeps a tap beside a chip from reading as a tap on it.
|
|
269
293
|
ENRMMathInlineAttachment *att = nil;
|
|
270
294
|
NSUInteger chipIdx = NSNotFound;
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
295
|
+
for (NSInteger probe = idx; probe >= idx - 1; probe--) {
|
|
296
|
+
if (probe < 0 || (NSUInteger)probe >= storage.length)
|
|
297
|
+
continue;
|
|
298
|
+
id v = [storage attribute:NSAttachmentAttributeName atIndex:(NSUInteger)probe effectiveRange:NULL];
|
|
299
|
+
if (![v isKindOfClass:[ENRMMathInlineAttachment class]])
|
|
300
|
+
continue;
|
|
301
|
+
// An empty rect means the layout could not give us the chip's extent; accept the
|
|
302
|
+
// candidate then, rather than making the chip untappable.
|
|
303
|
+
CGRect rect = [self mathChipRectInTextViewAtIndex:(NSUInteger)probe layoutManager:lm];
|
|
304
|
+
if (!CGRectIsEmpty(rect) && !CGRectContainsPoint(rect, loc))
|
|
305
|
+
continue;
|
|
306
|
+
att = v;
|
|
307
|
+
chipIdx = (NSUInteger)probe;
|
|
308
|
+
break;
|
|
285
309
|
}
|
|
286
310
|
if (!att)
|
|
287
311
|
return;
|
|
@@ -290,7 +314,6 @@ using namespace facebook::react;
|
|
|
290
314
|
[self clearMathChipSelectionsExcept:chipRange];
|
|
291
315
|
att.isSelected = YES;
|
|
292
316
|
[att invalidateRender];
|
|
293
|
-
NSLayoutManager *lm = storage.layoutManagers.firstObject;
|
|
294
317
|
if (lm) {
|
|
295
318
|
[lm invalidateLayoutForCharacterRange:chipRange actualCharacterRange:NULL];
|
|
296
319
|
[lm ensureLayoutForCharacterRange:chipRange];
|
|
@@ -306,10 +329,8 @@ using namespace facebook::react;
|
|
|
306
329
|
_suppressMathChipClearOnce = YES;
|
|
307
330
|
_textView.selectedRange = NSMakeRange(caretIndex, 0);
|
|
308
331
|
|
|
309
|
-
|
|
310
|
-
CGRect glyphRect = [
|
|
311
|
-
glyphRect.origin.x += _textView.textContainerInset.left;
|
|
312
|
-
glyphRect.origin.y += _textView.textContainerInset.top;
|
|
332
|
+
// Recomputed rather than reused from the hit-test: the layout was invalidated above.
|
|
333
|
+
CGRect glyphRect = [self mathChipRectInTextViewAtIndex:chipIdx layoutManager:lm];
|
|
313
334
|
CGRect rectInSelf = [self.contentView convertRect:glyphRect fromView:_textView];
|
|
314
335
|
|
|
315
336
|
[self emitOnMathPressWithLatex:att.latex start:chipIdx end:chipIdx + 1 displayMode:att.displayMode rect:rectInSelf];
|
|
@@ -338,6 +359,35 @@ using namespace facebook::react;
|
|
|
338
359
|
|
|
339
360
|
#endif
|
|
340
361
|
|
|
362
|
+
#pragma mark - Paste
|
|
363
|
+
|
|
364
|
+
- (void)emitOnPasteWithText:(NSString *)text markdown:(NSString *)markdown
|
|
365
|
+
{
|
|
366
|
+
auto emitter = [self getEventEmitter];
|
|
367
|
+
if (emitter == nullptr)
|
|
368
|
+
return;
|
|
369
|
+
emitter->onPaste({
|
|
370
|
+
.text = std::string([text UTF8String] ?: ""),
|
|
371
|
+
.markdown = std::string([markdown UTF8String] ?: ""),
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/// The single exit for an intercepted paste. One command rather than two makes
|
|
376
|
+
/// "never swallow a paste" structural: the branch that turns the clipboard into
|
|
377
|
+
/// something else still has to come through here, with empty strings.
|
|
378
|
+
- (void)resolvePaste:(NSString *)text markdown:(NSString *)markdown
|
|
379
|
+
{
|
|
380
|
+
// Round-trips the formatting when the copy came from an input of ours;
|
|
381
|
+
// without this a copy-then-paste inside the app would land as flat text.
|
|
382
|
+
if (markdown.length > 0) {
|
|
383
|
+
[self pasteMarkdown:markdown];
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
// Empty text with an empty selection is a zero-length edit: it still emits
|
|
387
|
+
// onChangeText with unchanged content, which the caller reads as a no-op.
|
|
388
|
+
[self replaceSelectedTextWith:text formattingRanges:@[]];
|
|
389
|
+
}
|
|
390
|
+
|
|
341
391
|
#pragma mark - State
|
|
342
392
|
|
|
343
393
|
- (void)updateState:(const facebook::react::State::Shared &)state
|
|
@@ -435,6 +485,10 @@ using namespace facebook::react;
|
|
|
435
485
|
}
|
|
436
486
|
}
|
|
437
487
|
|
|
488
|
+
if (newViewProps.interceptPaste != oldViewProps.interceptPaste) {
|
|
489
|
+
_interceptPaste = newViewProps.interceptPaste;
|
|
490
|
+
}
|
|
491
|
+
|
|
438
492
|
if (newViewProps.multiline != oldViewProps.multiline) {
|
|
439
493
|
_textView.textContainer.maximumNumberOfLines = newViewProps.multiline ? 0 : 1;
|
|
440
494
|
_textView.textContainer.lineBreakMode =
|
|
@@ -546,11 +600,20 @@ using namespace facebook::react;
|
|
|
546
600
|
writingDirectionChanged = YES;
|
|
547
601
|
}
|
|
548
602
|
|
|
603
|
+
// Must land before the defaultValue import below, so the first parse already sees
|
|
604
|
+
// the right flag. Assigned unconditionally, not just on change: the generated C++
|
|
605
|
+
// default is `false` while the JS default is `true`, so `blockSyntax={false}` on the
|
|
606
|
+
// first render compares equal to the old props and a change-guard would drop it.
|
|
607
|
+
BOOL blockSyntaxChanged = (_blockSyntax != (BOOL)newViewProps.blockSyntax);
|
|
608
|
+
_blockSyntax = newViewProps.blockSyntax;
|
|
609
|
+
|
|
549
610
|
if (newViewProps.defaultValue != oldViewProps.defaultValue) {
|
|
550
611
|
if (!newViewProps.defaultValue.empty() && oldViewProps.defaultValue.empty()) {
|
|
551
612
|
NSString *markdown = [NSString stringWithUTF8String:newViewProps.defaultValue.c_str()];
|
|
552
613
|
[self importMarkdown:markdown];
|
|
553
614
|
}
|
|
615
|
+
} else if (blockSyntaxChanged && _lastImportedMarkdown != nil) {
|
|
616
|
+
[self importMarkdown:_lastImportedMarkdown];
|
|
554
617
|
}
|
|
555
618
|
|
|
556
619
|
if (styleChanged) {
|
|
@@ -694,8 +757,9 @@ using namespace facebook::react;
|
|
|
694
757
|
|
|
695
758
|
- (void)importMarkdown:(NSString *)markdown
|
|
696
759
|
{
|
|
760
|
+
_lastImportedMarkdown = [markdown copy];
|
|
697
761
|
ENRMInputParser *parser = [[ENRMInputParser alloc] init];
|
|
698
|
-
ENRMParseResult *parsed = [parser parseToPlainTextAndRanges:markdown];
|
|
762
|
+
ENRMParseResult *parsed = [parser parseToPlainTextAndRanges:markdown blockSyntax:_blockSyntax];
|
|
699
763
|
|
|
700
764
|
_blockEmitting = YES;
|
|
701
765
|
|
|
@@ -754,6 +818,7 @@ using namespace facebook::react;
|
|
|
754
818
|
att.blockAlignment = _formatterStyle.mathBlockAlignment;
|
|
755
819
|
att.selectedBackgroundColor = _formatterStyle.mathBlockSelectedBackgroundColor;
|
|
756
820
|
att.selectedBorderColor = _formatterStyle.mathBlockSelectedBorderColor;
|
|
821
|
+
att.bold = ENRMMathFontWeightIsBold(_formatterStyle.mathBlockFontWeight);
|
|
757
822
|
} else {
|
|
758
823
|
att.fontSize = _formatterStyle.mathFontSize > 0 ? _formatterStyle.mathFontSize : 16.0;
|
|
759
824
|
att.mathTextColor = _formatterStyle.mathColor ?: _formatterStyle.baseTextColor;
|
|
@@ -768,6 +833,7 @@ using namespace facebook::react;
|
|
|
768
833
|
att.blockAlignment = NSTextAlignmentNatural;
|
|
769
834
|
att.selectedBackgroundColor = _formatterStyle.mathSelectedBackgroundColor;
|
|
770
835
|
att.selectedBorderColor = _formatterStyle.mathSelectedBorderColor;
|
|
836
|
+
att.bold = ENRMMathFontWeightIsBold(_formatterStyle.mathFontWeight);
|
|
771
837
|
}
|
|
772
838
|
}
|
|
773
839
|
|
|
@@ -854,7 +920,7 @@ using namespace facebook::react;
|
|
|
854
920
|
- (void)pasteMarkdown:(NSString *)markdown
|
|
855
921
|
{
|
|
856
922
|
ENRMInputParser *parser = [[ENRMInputParser alloc] init];
|
|
857
|
-
ENRMParseResult *parsed = [parser parseToPlainTextAndRanges:markdown];
|
|
923
|
+
ENRMParseResult *parsed = [parser parseToPlainTextAndRanges:markdown blockSyntax:_blockSyntax];
|
|
858
924
|
[self replaceSelectedTextWith:parsed.plainText formattingRanges:parsed.formattingRanges];
|
|
859
925
|
}
|
|
860
926
|
|
|
@@ -187,6 +187,12 @@ BOOL applyInputStyleProps(ENRMInputFormatterStyle *style, const InputProps &newP
|
|
|
187
187
|
style.mathSelectedBorderColor = (sbc && CGColorGetAlpha(sbc.CGColor) > 0) ? sbc : nil;
|
|
188
188
|
changed = YES;
|
|
189
189
|
}
|
|
190
|
+
if (newProps.markdownStyle.math.fontWeight != oldProps.markdownStyle.math.fontWeight) {
|
|
191
|
+
if (!newProps.markdownStyle.math.fontWeight.empty()) {
|
|
192
|
+
style.mathFontWeight = [[NSString alloc] initWithUTF8String:newProps.markdownStyle.math.fontWeight.c_str()];
|
|
193
|
+
changed = YES;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
190
196
|
|
|
191
197
|
// Math block (`$$...$$`)
|
|
192
198
|
if (newProps.markdownStyle.mathBlock.color != oldProps.markdownStyle.mathBlock.color) {
|
|
@@ -237,6 +243,13 @@ BOOL applyInputStyleProps(ENRMInputFormatterStyle *style, const InputProps &newP
|
|
|
237
243
|
style.mathBlockSelectedBorderColor = (sbc && CGColorGetAlpha(sbc.CGColor) > 0) ? sbc : nil;
|
|
238
244
|
changed = YES;
|
|
239
245
|
}
|
|
246
|
+
if (newProps.markdownStyle.mathBlock.fontWeight != oldProps.markdownStyle.mathBlock.fontWeight) {
|
|
247
|
+
if (!newProps.markdownStyle.mathBlock.fontWeight.empty()) {
|
|
248
|
+
style.mathBlockFontWeight =
|
|
249
|
+
[[NSString alloc] initWithUTF8String:newProps.markdownStyle.mathBlock.fontWeight.c_str()];
|
|
250
|
+
changed = YES;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
240
253
|
if (newProps.markdownStyle.mathBlock.marginTop != oldProps.markdownStyle.mathBlock.marginTop) {
|
|
241
254
|
style.mathBlockMarginTop = newProps.markdownStyle.mathBlock.marginTop;
|
|
242
255
|
changed = YES;
|
|
@@ -131,6 +131,7 @@ template <typename StyleStruct> inline size_t computeStyleFingerprint(const Styl
|
|
|
131
131
|
hashFields(s.table.headerFontFamily, s.table.cellPaddingHorizontal, s.table.cellPaddingVertical, s.table.borderWidth,
|
|
132
132
|
s.table.borderRadius);
|
|
133
133
|
hashFields(s.math.fontSize, s.math.padding, s.math.marginTop, s.math.marginBottom, s.math.textAlign);
|
|
134
|
+
hashFields(s.inlineMath.paddingVertical);
|
|
134
135
|
hashFields(s.taskList.checkboxSize, s.taskList.checkboxBorderRadius);
|
|
135
136
|
|
|
136
137
|
return h;
|
|
@@ -10,17 +10,45 @@ import AppKit
|
|
|
10
10
|
private typealias UIColor = NSColor
|
|
11
11
|
#endif
|
|
12
12
|
|
|
13
|
+
/// Weight a formula is typeset at.
|
|
14
|
+
///
|
|
15
|
+
/// An enum rather than the `BOOL` that crosses the ObjC boundary so the draw
|
|
16
|
+
/// path's switch turns a third weight into a compile error. Mirrors
|
|
17
|
+
/// MathFontWeight.kt on Android.
|
|
18
|
+
private enum MathFontWeight {
|
|
19
|
+
case normal
|
|
20
|
+
case bold
|
|
21
|
+
|
|
22
|
+
init(bold: Bool) {
|
|
23
|
+
self = bold ? .bold : .normal
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Stroke added to each glyph outline, as a fraction of the em size. Scales
|
|
27
|
+
/// with the formula so a display block and an inline fraction read alike.
|
|
28
|
+
var strokeEmRatio: CGFloat {
|
|
29
|
+
switch self {
|
|
30
|
+
case .normal: return 0
|
|
31
|
+
case .bold: return 0.035
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
13
36
|
@objc(ENRMRaTeXRenderResult)
|
|
14
37
|
public final class ENRMRaTeXRenderResult: NSObject {
|
|
15
38
|
private let renderer: RaTeXRenderer
|
|
39
|
+
/// Non-zero only in bold mode: half of it grows the glyph ink on each side.
|
|
40
|
+
private let boldStrokeWidth: CGFloat
|
|
41
|
+
private let boldStrokeColor: CGColor?
|
|
16
42
|
|
|
17
43
|
@objc public let width: CGFloat
|
|
18
44
|
@objc public let ascent: CGFloat
|
|
19
45
|
@objc public let descent: CGFloat
|
|
20
46
|
@objc public var totalHeight: CGFloat { ascent + descent }
|
|
21
47
|
|
|
22
|
-
init(renderer: RaTeXRenderer) {
|
|
48
|
+
init(renderer: RaTeXRenderer, boldStrokeWidth: CGFloat, boldStrokeColor: CGColor?) {
|
|
23
49
|
self.renderer = renderer
|
|
50
|
+
self.boldStrokeWidth = boldStrokeWidth
|
|
51
|
+
self.boldStrokeColor = boldStrokeColor
|
|
24
52
|
self.width = renderer.width
|
|
25
53
|
self.ascent = renderer.height
|
|
26
54
|
self.descent = renderer.depth
|
|
@@ -28,7 +56,22 @@ public final class ENRMRaTeXRenderResult: NSObject {
|
|
|
28
56
|
}
|
|
29
57
|
|
|
30
58
|
@objc public func draw(in context: CGContext) {
|
|
59
|
+
guard boldStrokeWidth > 0, let boldStrokeColor else {
|
|
60
|
+
renderer.draw(in: context)
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
// Synthetic bold: stroke each glyph outline over its fill, the only way to
|
|
64
|
+
// add weight without moving glyphs whose positions RaTeX has already fixed
|
|
65
|
+
// (the KaTeX bold faces run up to 15% wider and would collide). It reaches
|
|
66
|
+
// every glyph because RaTeXRenderer.drawGlyph sets no text drawing mode of
|
|
67
|
+
// its own, including the paths RaTeX strokes itself (\cancel, \textcircled),
|
|
68
|
+
// which is why bold is opt-in per surface.
|
|
69
|
+
context.saveGState()
|
|
70
|
+
context.setTextDrawingMode(.fillStroke)
|
|
71
|
+
context.setLineWidth(boldStrokeWidth)
|
|
72
|
+
context.setStrokeColor(boldStrokeColor)
|
|
31
73
|
renderer.draw(in: context)
|
|
74
|
+
context.restoreGState()
|
|
32
75
|
}
|
|
33
76
|
}
|
|
34
77
|
|
|
@@ -43,13 +86,19 @@ public final class ENRMRaTeXBridge: NSObject {
|
|
|
43
86
|
_ latex: String,
|
|
44
87
|
displayMode: Bool,
|
|
45
88
|
fontSize: CGFloat,
|
|
46
|
-
color: UIColor
|
|
89
|
+
color: UIColor,
|
|
90
|
+
bold: Bool
|
|
47
91
|
) -> ENRMRaTeXRenderResult? {
|
|
48
92
|
RaTeXFontLoader.ensureLoaded()
|
|
49
93
|
do {
|
|
50
94
|
let displayList = try RaTeXEngine.shared.parse(latex, displayMode: displayMode, color: color)
|
|
51
95
|
let renderer = RaTeXRenderer(displayList: displayList, fontSize: fontSize)
|
|
52
|
-
|
|
96
|
+
let strokeWidth = fontSize * MathFontWeight(bold: bold).strokeEmRatio
|
|
97
|
+
return ENRMRaTeXRenderResult(
|
|
98
|
+
renderer: renderer,
|
|
99
|
+
boldStrokeWidth: strokeWidth,
|
|
100
|
+
boldStrokeColor: strokeWidth > 0 ? color.cgColor : nil
|
|
101
|
+
)
|
|
53
102
|
} catch {
|
|
54
103
|
NSLog("[RaTeX] Failed to parse LaTeX: %@", error.localizedDescription)
|
|
55
104
|
return nil
|
|
@@ -11,6 +11,14 @@
|
|
|
11
11
|
|
|
12
12
|
+ (instancetype)defaultFlags;
|
|
13
13
|
|
|
14
|
+
/// Flags matching the codegen `md4cFlags` Props defaults (every flag off).
|
|
15
|
+
///
|
|
16
|
+
/// Components mirror `md4cFlags` into an ivar with a per-field diff against the
|
|
17
|
+
/// props baseline, so the ivar has to start from the same baseline the props do.
|
|
18
|
+
/// `defaultFlags` enables `latexMath`, which is the right default for the
|
|
19
|
+
/// standalone parser API but would make a `latexMath: false` prop a no-op.
|
|
20
|
+
+ (instancetype)propsDefaultFlags;
|
|
21
|
+
|
|
14
22
|
@end
|
|
15
23
|
|
|
16
24
|
@interface ENRMMarkdownParser : NSObject
|
|
@@ -22,6 +22,17 @@ extern MarkdownASTNode *parseMarkdownWithCppParser(NSString *markdown, ENRMMd4cF
|
|
|
22
22
|
return [[ENRMMd4cFlags alloc] init];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
+ (instancetype)propsDefaultFlags
|
|
26
|
+
{
|
|
27
|
+
ENRMMd4cFlags *flags = [[ENRMMd4cFlags alloc] init];
|
|
28
|
+
flags.underline = NO;
|
|
29
|
+
flags.latexMath = NO;
|
|
30
|
+
flags.superscript = NO;
|
|
31
|
+
flags.subscript = NO;
|
|
32
|
+
flags.highlight = NO;
|
|
33
|
+
return flags;
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
- (id)copyWithZone:(NSZone *)zone
|
|
26
37
|
{
|
|
27
38
|
ENRMMd4cFlags *copy = [[ENRMMd4cFlags allocWithZone:zone] init];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#import "ENRMMathInlineRenderer.h"
|
|
2
|
+
#import "ENRMMathFontWeight.h"
|
|
2
3
|
#import "ENRMMathInlineAttachment.h"
|
|
3
4
|
#import "MarkdownASTNode.h"
|
|
4
5
|
#import "RenderContext.h"
|
|
@@ -25,6 +26,8 @@
|
|
|
25
26
|
attachment.latex = latex;
|
|
26
27
|
attachment.fontSize = currentFont ? currentFont.pointSize : [_config paragraphFontSize];
|
|
27
28
|
attachment.mathTextColor = [_config inlineMathColor];
|
|
29
|
+
attachment.containerPaddingVertical = [_config inlineMathPaddingVertical];
|
|
30
|
+
attachment.bold = ENRMMathFontWeightIsBold([_config inlineMathFontWeight]);
|
|
28
31
|
|
|
29
32
|
#if TARGET_OS_OSX
|
|
30
33
|
// On macOS, NSLayoutManager uses self.image/self.bounds rather than calling
|
|
@@ -109,15 +109,18 @@ NSString *const TaskIndexAttribute = @"TaskIndex";
|
|
|
109
109
|
style.firstLineHeadIndent = totalIndent;
|
|
110
110
|
style.headIndent = totalIndent;
|
|
111
111
|
|
|
112
|
-
if (lineHeightConfig > 0) {
|
|
113
|
-
style.minimumLineHeight = lineHeightConfig;
|
|
114
|
-
style.maximumLineHeight = lineHeightConfig;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
112
|
NSMutableDictionary *attributesToApply = [metadata mutableCopy];
|
|
118
113
|
attributesToApply[NSParagraphStyleAttributeName] = style;
|
|
119
114
|
|
|
120
115
|
[output addAttributes:attributesToApply range:range];
|
|
116
|
+
|
|
117
|
+
// Line height goes through the shared helper so list items get the same math
|
|
118
|
+
// carve-out as paragraphs. Setting maximumLineHeight here directly would clamp
|
|
119
|
+
// the line fragment below the height an inline math attachment draws at, and the
|
|
120
|
+
// overflow paints over the neighbouring lines. applyLineHeight reads back the
|
|
121
|
+
// paragraph style we just applied, so the indents above survive, and it
|
|
122
|
+
// early-returns on a non-positive line height like the old guard did.
|
|
123
|
+
applyLineHeight(output, range, lineHeightConfig);
|
|
121
124
|
}];
|
|
122
125
|
|
|
123
126
|
if (isTask && isChecked) {
|
package/ios/styles/StyleConfig.h
CHANGED
|
@@ -378,10 +378,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
378
378
|
- (void)setMathMarginBottom:(CGFloat)newValue;
|
|
379
379
|
- (NSString *)mathTextAlign;
|
|
380
380
|
- (void)setMathTextAlign:(NSString *)newValue;
|
|
381
|
+
- (NSString *)mathFontWeight;
|
|
382
|
+
- (void)setMathFontWeight:(NSString *)newValue;
|
|
381
383
|
|
|
382
384
|
// Inline Math properties
|
|
383
385
|
- (RCTUIColor *)inlineMathColor;
|
|
384
386
|
- (void)setInlineMathColor:(RCTUIColor *)newValue;
|
|
387
|
+
- (CGFloat)inlineMathPaddingVertical;
|
|
388
|
+
- (void)setInlineMathPaddingVertical:(CGFloat)newValue;
|
|
389
|
+
- (NSString *)inlineMathFontWeight;
|
|
390
|
+
- (void)setInlineMathFontWeight:(NSString *)newValue;
|
|
385
391
|
// Spoiler properties
|
|
386
392
|
- (RCTUIColor *)spoilerColor;
|
|
387
393
|
- (void)setSpoilerColor:(RCTUIColor *)newValue;
|