react-native-enriched-markdown-scaffold 1.0.2-scaffold.4 → 1.0.2-scaffold.5
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/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +12 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +2 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +12 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +2 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +74 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +68 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +10 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +2 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +107 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +19 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +48 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/SelectionChangeEvent.kt +42 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionChangeReporter.kt +230 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +11 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +8 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +8 -1
- package/docs/API_REFERENCE.md +58 -0
- package/ios/EnrichedMarkdown.mm +174 -2
- package/ios/EnrichedMarkdownText.mm +103 -1
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +74 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +68 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +10 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +2 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +50 -2
- package/ios/utils/ENRMLinkChip.m +14 -14
- package/ios/utils/ENRMLinkLayout.m +12 -12
- package/ios/utils/ENRMSelectionChange.h +96 -0
- package/ios/utils/ENRMSelectionChange.m +204 -0
- package/ios/utils/EditMenuUtils+macOS.m +1 -1
- package/ios/utils/MarkdownAccessibilityElementBuilder.m +1 -2
- package/ios/views/ENRMCodeBlockContainerView.h +3 -0
- package/ios/views/ENRMCodeBlockContainerView.m +3 -0
- package/ios/views/ENRMMathContainerView.h +3 -0
- package/ios/views/ENRMMathContainerView.m +3 -0
- package/ios/views/TableContainerView.h +3 -0
- package/ios/views/TableContainerView.m +4 -1
- package/lib/module/EnrichedMarkdownNativeComponent.ts +60 -1
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +60 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/jest/index.js +13 -0
- package/lib/module/jest/index.js.map +1 -1
- package/lib/module/native/EnrichedMarkdownText.js +44 -4
- package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +53 -2
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +53 -2
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/jest/index.d.ts +1 -1
- package/lib/typescript/src/jest/index.d.ts.map +1 -1
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +5 -5
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.d.ts +36 -3
- package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +36 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/EnrichedMarkdownNativeComponent.ts +60 -1
- package/src/EnrichedMarkdownTextNativeComponent.ts +60 -1
- package/src/index.tsx +3 -0
- package/src/jest/index.tsx +21 -1
- package/src/native/EnrichedMarkdownText.tsx +85 -9
- package/src/types/MarkdownTextProps.ts +43 -2
- package/src/types/events.ts +38 -0
package/ios/EnrichedMarkdown.mm
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
#import "ENRMMathContainerView.h"
|
|
20
20
|
#endif
|
|
21
21
|
#import "ENRMCodeBlockContainerView.h"
|
|
22
|
+
#import "ENRMLinkLayout.h"
|
|
23
|
+
#import "ENRMSelectionChange.h"
|
|
22
24
|
#import "ENRMSpoilerCapable.h"
|
|
23
25
|
#import "ENRMSpoilerOverlayView.h"
|
|
24
26
|
#import "ENRMSpoilerTapUtils.h"
|
|
@@ -38,7 +40,6 @@
|
|
|
38
40
|
#import "SegmentReconciler.h"
|
|
39
41
|
#import "SegmentRenderer.h"
|
|
40
42
|
#import "SegmentViewRegistry.h"
|
|
41
|
-
#import "ENRMLinkLayout.h"
|
|
42
43
|
#import "SelectionColorUtils.h"
|
|
43
44
|
#import "StreamingMarkdownFilter.h"
|
|
44
45
|
#import "StyleConfig.h"
|
|
@@ -128,6 +129,15 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
128
129
|
BOOL _emitLinkLayout;
|
|
129
130
|
NSArray<NSDictionary *> *_lastLinkLayout;
|
|
130
131
|
|
|
132
|
+
ENRMSelectionChangeReporter *_selectionReporter;
|
|
133
|
+
// At most one segment holds a selection; a new one clears the previous.
|
|
134
|
+
__weak ENRMPlatformTextView *_selectionOwner;
|
|
135
|
+
// A block long-pressed while contextMenuHidden is on, reported as the selection.
|
|
136
|
+
__weak RCTUIView *_activeBlockView;
|
|
137
|
+
NSString *_activeBlockSource;
|
|
138
|
+
NSString *_activeBlockMarkdown;
|
|
139
|
+
NSString *_activeBlockText;
|
|
140
|
+
|
|
131
141
|
NSLineBreakStrategy _lineBreakStrategy;
|
|
132
142
|
|
|
133
143
|
ENRMWritingDirectionMode _writingDirectionMode;
|
|
@@ -199,10 +209,117 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
199
209
|
[strongSelf renderMarkdownContent:strongSelf->_cachedMarkdown];
|
|
200
210
|
}
|
|
201
211
|
};
|
|
212
|
+
|
|
213
|
+
_selectionReporter = [[ENRMSelectionChangeReporter alloc]
|
|
214
|
+
initWithSnapshot:^NSDictionary * {
|
|
215
|
+
EnrichedMarkdown *strongSelf = weakSelf;
|
|
216
|
+
return strongSelf ? [strongSelf selectionPayload] : ENRMInactiveSelectionPayload();
|
|
217
|
+
}
|
|
218
|
+
emit:^(NSDictionary *payload) {
|
|
219
|
+
EnrichedMarkdown *strongSelf = weakSelf;
|
|
220
|
+
if (!strongSelf)
|
|
221
|
+
return;
|
|
222
|
+
auto emitter = std::static_pointer_cast<EnrichedMarkdownEventEmitter const>(strongSelf->_eventEmitter);
|
|
223
|
+
if (emitter)
|
|
224
|
+
emitter->onSelectionChange(
|
|
225
|
+
ENRMSelectionChangeEventFromPayload<EnrichedMarkdownEventEmitter::OnSelectionChange>(payload));
|
|
226
|
+
}];
|
|
202
227
|
}
|
|
203
228
|
return self;
|
|
204
229
|
}
|
|
205
230
|
|
|
231
|
+
#pragma mark - Selection
|
|
232
|
+
|
|
233
|
+
/// The current selection (or active block) as an `onSelectionChange` payload.
|
|
234
|
+
/// Markdown and `whole` follow the same rules as the intercepted Copy.
|
|
235
|
+
- (NSDictionary *)selectionPayload
|
|
236
|
+
{
|
|
237
|
+
RCTUIView *blockView = _activeBlockView;
|
|
238
|
+
if (blockView != nil) {
|
|
239
|
+
if (blockView.superview != self)
|
|
240
|
+
return ENRMInactiveSelectionPayload();
|
|
241
|
+
return ENRMBlockSelectionPayload(_activeBlockSource, _activeBlockMarkdown, _activeBlockText, blockView.frame);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#if !TARGET_OS_OSX
|
|
245
|
+
UITextView *owner = _selectionOwner;
|
|
246
|
+
if (owner == nil || ![owner isDescendantOfView:self])
|
|
247
|
+
return ENRMInactiveSelectionPayload();
|
|
248
|
+
NSDictionary *selection = ENRMTextSelectionInTextView(owner, self);
|
|
249
|
+
if (!selection)
|
|
250
|
+
return ENRMInactiveSelectionPayload();
|
|
251
|
+
|
|
252
|
+
NSString *text = selection[ENRMSelectionTextKey];
|
|
253
|
+
// Segments only see their own text, so a selection is the whole component
|
|
254
|
+
// only when it spans the sole segment; the markdown is then the original.
|
|
255
|
+
BOOL whole = [selection[ENRMSelectionFullKey] boolValue] && _segmentViews.count == 1 && _cachedMarkdown.length > 0;
|
|
256
|
+
NSString *markdown =
|
|
257
|
+
whole ? _cachedMarkdown : extractMarkdownFromAttributedString(owner.attributedText, owner.selectedRange);
|
|
258
|
+
NSMutableDictionary *payload = [selection mutableCopy];
|
|
259
|
+
[payload removeObjectForKey:ENRMSelectionFullKey];
|
|
260
|
+
payload[ENRMSelectionActiveKey] = @YES;
|
|
261
|
+
payload[ENRMSelectionSourceKey] = @"selection";
|
|
262
|
+
payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
|
|
263
|
+
payload[ENRMSelectionWholeKey] = @(whole);
|
|
264
|
+
return payload;
|
|
265
|
+
#else
|
|
266
|
+
return ENRMInactiveSelectionPayload();
|
|
267
|
+
#endif
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
- (void)clearActiveBlock
|
|
271
|
+
{
|
|
272
|
+
_activeBlockView = nil;
|
|
273
|
+
_activeBlockSource = nil;
|
|
274
|
+
_activeBlockMarkdown = nil;
|
|
275
|
+
_activeBlockText = nil;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
- (void)clearSegmentSelection:(ENRMPlatformTextView *)textView
|
|
279
|
+
{
|
|
280
|
+
#if !TARGET_OS_OSX
|
|
281
|
+
textView.selectedRange = NSMakeRange(0, 0);
|
|
282
|
+
[textView resignFirstResponder];
|
|
283
|
+
#endif
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
- (void)clearSelection
|
|
287
|
+
{
|
|
288
|
+
ENRMPlatformTextView *owner = _selectionOwner;
|
|
289
|
+
_selectionOwner = nil;
|
|
290
|
+
[self clearActiveBlock];
|
|
291
|
+
if (owner)
|
|
292
|
+
[self clearSegmentSelection:owner];
|
|
293
|
+
[_selectionReporter flushNow];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
|
297
|
+
{
|
|
298
|
+
RCTEnrichedMarkdownHandleCommand(self, commandName, args);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
- (ENRMBlockCopyRequestBlock)blockMenuSuppressedForSource:(NSString *)source view:(RCTUIView *)view
|
|
302
|
+
{
|
|
303
|
+
__weak EnrichedMarkdown *weakSelf = self;
|
|
304
|
+
__weak RCTUIView *weakView = view;
|
|
305
|
+
return ^(NSString *markdown, NSString *text) {
|
|
306
|
+
EnrichedMarkdown *strongSelf = weakSelf;
|
|
307
|
+
RCTUIView *strongView = weakView;
|
|
308
|
+
if (!strongSelf || !strongView || !strongSelf->_selectionReporter.enabled)
|
|
309
|
+
return;
|
|
310
|
+
ENRMPlatformTextView *owner = strongSelf->_selectionOwner;
|
|
311
|
+
strongSelf->_selectionOwner = nil;
|
|
312
|
+
if (owner)
|
|
313
|
+
[strongSelf clearSegmentSelection:owner];
|
|
314
|
+
strongSelf->_activeBlockView = strongView;
|
|
315
|
+
strongSelf->_activeBlockSource = source;
|
|
316
|
+
strongSelf->_activeBlockMarkdown = markdown;
|
|
317
|
+
strongSelf->_activeBlockText = text;
|
|
318
|
+
[strongSelf->_selectionReporter forgetLastReported];
|
|
319
|
+
[strongSelf->_selectionReporter flushNow];
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
206
323
|
- (void)configureSegmentViewRegistry
|
|
207
324
|
{
|
|
208
325
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
@@ -839,6 +956,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
839
956
|
tableView.contextMenuHidden = _contextMenuHidden;
|
|
840
957
|
tableView.menuOptions = [self blockMenuOptions];
|
|
841
958
|
tableView.onCopyRequest = [self blockCopyRequestForSource:@"table"];
|
|
959
|
+
tableView.onMenuSuppressed = [self blockMenuSuppressedForSource:@"table" view:tableView];
|
|
842
960
|
|
|
843
961
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
844
962
|
|
|
@@ -881,6 +999,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
881
999
|
mathView.contextMenuHidden = _contextMenuHidden;
|
|
882
1000
|
mathView.menuOptions = [self blockMenuOptions];
|
|
883
1001
|
mathView.onCopyRequest = [self blockCopyRequestForSource:@"math"];
|
|
1002
|
+
mathView.onMenuSuppressed = [self blockMenuSuppressedForSource:@"math" view:mathView];
|
|
884
1003
|
[mathView applyLatex:mathSegment.latex];
|
|
885
1004
|
return mathView;
|
|
886
1005
|
}
|
|
@@ -894,6 +1013,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
894
1013
|
codeBlockView.contextMenuHidden = _contextMenuHidden;
|
|
895
1014
|
codeBlockView.menuOptions = [self blockMenuOptions];
|
|
896
1015
|
codeBlockView.onCopyRequest = [self blockCopyRequestForSource:@"code"];
|
|
1016
|
+
codeBlockView.onMenuSuppressed = [self blockMenuSuppressedForSource:@"code" view:codeBlockView];
|
|
897
1017
|
|
|
898
1018
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
899
1019
|
codeBlockView.onCopyPress = ^(NSString *code, NSString *language) {
|
|
@@ -947,6 +1067,8 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
947
1067
|
[super layoutSubviews];
|
|
948
1068
|
[self computeSegmentLayoutForWidth:self.bounds.size.width applyFrames:YES];
|
|
949
1069
|
[self emitLinkLayoutIfNeeded];
|
|
1070
|
+
// Segments may have moved or been replaced; re-read the selection (deduplicated).
|
|
1071
|
+
[_selectionReporter schedule];
|
|
950
1072
|
}
|
|
951
1073
|
|
|
952
1074
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
@@ -988,6 +1110,8 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
988
1110
|
[self setNeedsLayout];
|
|
989
1111
|
}
|
|
990
1112
|
|
|
1113
|
+
_selectionReporter.enabled = newViewProps.emitSelectionChange;
|
|
1114
|
+
|
|
991
1115
|
for (RCTUIView *segment in _segmentViews) {
|
|
992
1116
|
if ([segment isKindOfClass:[EnrichedMarkdownInternalText class]]) {
|
|
993
1117
|
EnrichedMarkdownInternalText *textSegment = (EnrichedMarkdownInternalText *)segment;
|
|
@@ -1185,6 +1309,9 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
1185
1309
|
_config = nil;
|
|
1186
1310
|
_emitLinkLayout = NO;
|
|
1187
1311
|
_lastLinkLayout = nil;
|
|
1312
|
+
_selectionReporter.enabled = NO;
|
|
1313
|
+
_selectionOwner = nil;
|
|
1314
|
+
[self clearActiveBlock];
|
|
1188
1315
|
_md4cFlags = [EnrichedMarkdown flagsFromProps:resetProps->md4cFlags];
|
|
1189
1316
|
_maxFontSizeMultiplier = 0;
|
|
1190
1317
|
_allowTrailingMargin = NO;
|
|
@@ -1406,14 +1533,33 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1406
1533
|
ENRMHandleTapOnTextView(textView, recognizer, ^(NSString *url) { [self emitLinkPress:url]; });
|
|
1407
1534
|
}
|
|
1408
1535
|
|
|
1536
|
+
#if !TARGET_OS_OSX
|
|
1537
|
+
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
1538
|
+
{
|
|
1539
|
+
if (textView.selectedRange.length > 0) {
|
|
1540
|
+
// Take ownership first so the previous owner's own "cleared" callback is ignored.
|
|
1541
|
+
ENRMPlatformTextView *previous = _selectionOwner;
|
|
1542
|
+
_selectionOwner = textView;
|
|
1543
|
+
[self clearActiveBlock];
|
|
1544
|
+
if (previous && previous != textView)
|
|
1545
|
+
previous.selectedRange = NSMakeRange(0, 0);
|
|
1546
|
+
[_selectionReporter schedule];
|
|
1547
|
+
} else if (textView == _selectionOwner) {
|
|
1548
|
+
[_selectionReporter selectionChanged:NO];
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
#endif
|
|
1552
|
+
|
|
1409
1553
|
// TODO: Remove API_AVAILABLE(ios(16.0)) guard when the minimum iOS deployment target in RN is bumped to 16.
|
|
1410
1554
|
#if !TARGET_OS_OSX
|
|
1411
1555
|
- (UIMenu *)textView:(UITextView *)textView
|
|
1412
1556
|
editMenuForTextInRange:(NSRange)range
|
|
1413
1557
|
suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0))
|
|
1414
1558
|
{
|
|
1559
|
+
// An empty menu presents nothing; nil would make UIKit show its default menu
|
|
1560
|
+
// (the selection and handles stay either way).
|
|
1415
1561
|
if (_contextMenuHidden) {
|
|
1416
|
-
return
|
|
1562
|
+
return [UIMenu menuWithChildren:@[]];
|
|
1417
1563
|
}
|
|
1418
1564
|
|
|
1419
1565
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
@@ -1448,6 +1594,32 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1448
1594
|
customActions, _selectionMenuConfig, onCopyRequest);
|
|
1449
1595
|
}
|
|
1450
1596
|
|
|
1597
|
+
// Attachments other than images (inline math) are text, not items: without
|
|
1598
|
+
// this a long press on one in an unfocused text view starts UIKit's text item
|
|
1599
|
+
// interaction, which presents nothing and leaves the view unable to select.
|
|
1600
|
+
- (BOOL)textView:(UITextView *)textView
|
|
1601
|
+
shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment
|
|
1602
|
+
inRange:(NSRange)characterRange
|
|
1603
|
+
interaction:(UITextItemInteraction)interaction
|
|
1604
|
+
{
|
|
1605
|
+
if ([textAttachment isKindOfClass:[ENRMImageAttachment class]]) {
|
|
1606
|
+
return YES;
|
|
1607
|
+
}
|
|
1608
|
+
// A long press selects the attachment like a word, as it does once the view is focused.
|
|
1609
|
+
if (interaction == UITextItemInteractionPresentActions) {
|
|
1610
|
+
__weak UITextView *weakTextView = textView;
|
|
1611
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1612
|
+
UITextView *strongTextView = weakTextView;
|
|
1613
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
[strongTextView becomeFirstResponder];
|
|
1617
|
+
strongTextView.selectedRange = characterRange;
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
return NO;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1451
1623
|
- (BOOL)textView:(UITextView *)textView
|
|
1452
1624
|
shouldInteractWithURL:(NSURL *)URL
|
|
1453
1625
|
inRange:(NSRange)characterRange
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#import "ENRMImageAttachment.h"
|
|
9
9
|
#import "ENRMLinkLayout.h"
|
|
10
10
|
#import "ENRMMarkdownParser.h"
|
|
11
|
+
#import "ENRMSelectionChange.h"
|
|
11
12
|
#import "ENRMSpoilerOverlayManager.h"
|
|
12
13
|
#import "ENRMSpoilerTapUtils.h"
|
|
13
14
|
#import "ENRMTailFadeInAnimator.h"
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
#import "MarkdownExtractor.h"
|
|
27
28
|
#import "MeasurementCache.h"
|
|
28
29
|
#import "ParagraphStyleUtils.h"
|
|
30
|
+
#import "PasteboardUtils.h"
|
|
29
31
|
#import "RuntimeKeys.h"
|
|
30
32
|
#import "SelectionColorUtils.h"
|
|
31
33
|
#import "StylePropsUtils.h"
|
|
@@ -115,6 +117,8 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
115
117
|
BOOL _emitLinkLayout;
|
|
116
118
|
NSArray<NSDictionary *> *_lastLinkLayout;
|
|
117
119
|
|
|
120
|
+
ENRMSelectionChangeReporter *_selectionReporter;
|
|
121
|
+
|
|
118
122
|
NSLineBreakStrategy _lineBreakStrategy;
|
|
119
123
|
|
|
120
124
|
ENRMWritingDirectionMode _writingDirectionMode;
|
|
@@ -272,11 +276,68 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
272
276
|
};
|
|
273
277
|
|
|
274
278
|
[self setupTextView];
|
|
279
|
+
[self setupSelectionReporter];
|
|
275
280
|
}
|
|
276
281
|
|
|
277
282
|
return self;
|
|
278
283
|
}
|
|
279
284
|
|
|
285
|
+
- (void)setupSelectionReporter
|
|
286
|
+
{
|
|
287
|
+
__weak EnrichedMarkdownText *weakSelf = self;
|
|
288
|
+
_selectionReporter = [[ENRMSelectionChangeReporter alloc]
|
|
289
|
+
initWithSnapshot:^NSDictionary * {
|
|
290
|
+
EnrichedMarkdownText *strongSelf = weakSelf;
|
|
291
|
+
return strongSelf ? [strongSelf selectionPayload] : ENRMInactiveSelectionPayload();
|
|
292
|
+
}
|
|
293
|
+
emit:^(NSDictionary *payload) {
|
|
294
|
+
EnrichedMarkdownText *strongSelf = weakSelf;
|
|
295
|
+
if (!strongSelf)
|
|
296
|
+
return;
|
|
297
|
+
auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(strongSelf->_eventEmitter);
|
|
298
|
+
if (emitter)
|
|
299
|
+
emitter->onSelectionChange(
|
|
300
|
+
ENRMSelectionChangeEventFromPayload<EnrichedMarkdownTextEventEmitter::OnSelectionChange>(payload));
|
|
301
|
+
}];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/// The current selection as an `onSelectionChange` payload. Markdown and
|
|
305
|
+
/// `whole` follow the same rules as the intercepted Copy (`onCopyRequest`).
|
|
306
|
+
- (NSDictionary *)selectionPayload
|
|
307
|
+
{
|
|
308
|
+
#if !TARGET_OS_OSX
|
|
309
|
+
NSDictionary *selection = ENRMTextSelectionInTextView(_textView, self);
|
|
310
|
+
if (!selection)
|
|
311
|
+
return ENRMInactiveSelectionPayload();
|
|
312
|
+
|
|
313
|
+
NSString *text = selection[ENRMSelectionTextKey];
|
|
314
|
+
NSString *markdown = markdownForRange(_textView.attributedText, _textView.selectedRange, _cachedMarkdown);
|
|
315
|
+
NSMutableDictionary *payload = [selection mutableCopy];
|
|
316
|
+
[payload removeObjectForKey:ENRMSelectionFullKey];
|
|
317
|
+
payload[ENRMSelectionActiveKey] = @YES;
|
|
318
|
+
payload[ENRMSelectionSourceKey] = @"selection";
|
|
319
|
+
payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
|
|
320
|
+
payload[ENRMSelectionWholeKey] = @([selection[ENRMSelectionFullKey] boolValue] && _cachedMarkdown.length > 0);
|
|
321
|
+
return payload;
|
|
322
|
+
#else
|
|
323
|
+
return ENRMInactiveSelectionPayload();
|
|
324
|
+
#endif
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
- (void)clearSelection
|
|
328
|
+
{
|
|
329
|
+
#if !TARGET_OS_OSX
|
|
330
|
+
_textView.selectedRange = NSMakeRange(0, 0);
|
|
331
|
+
[_textView resignFirstResponder];
|
|
332
|
+
#endif
|
|
333
|
+
[_selectionReporter flushNow];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
|
337
|
+
{
|
|
338
|
+
RCTEnrichedMarkdownTextHandleCommand(self, commandName, args);
|
|
339
|
+
}
|
|
340
|
+
|
|
280
341
|
- (void)setupTextView
|
|
281
342
|
{
|
|
282
343
|
#if !TARGET_OS_OSX
|
|
@@ -477,6 +538,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
477
538
|
[self emitLinkLayoutIfNeeded];
|
|
478
539
|
}
|
|
479
540
|
|
|
541
|
+
// New text drops the selection; setting attributedText doesn't call the delegate.
|
|
542
|
+
[_selectionReporter schedule];
|
|
543
|
+
|
|
480
544
|
if (_textView.hidden) {
|
|
481
545
|
dispatch_async(dispatch_get_main_queue(), ^{ self->_textView.hidden = NO; });
|
|
482
546
|
}
|
|
@@ -539,6 +603,8 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
539
603
|
[self emitLinkLayoutIfNeeded];
|
|
540
604
|
}
|
|
541
605
|
|
|
606
|
+
_selectionReporter.enabled = newViewProps.emitSelectionChange;
|
|
607
|
+
|
|
542
608
|
if (_textView.selectable != newViewProps.selectable) {
|
|
543
609
|
_textView.selectable = newViewProps.selectable;
|
|
544
610
|
}
|
|
@@ -717,6 +783,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
717
783
|
_spoilerManager = nil;
|
|
718
784
|
_emitLinkLayout = NO;
|
|
719
785
|
_lastLinkLayout = nil;
|
|
786
|
+
_selectionReporter.enabled = NO;
|
|
720
787
|
if (_textView != nil) {
|
|
721
788
|
ENRMSetAttributedText(_textView, [[NSAttributedString alloc] initWithString:@""]);
|
|
722
789
|
_textView.hidden = YES;
|
|
@@ -839,6 +906,32 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
839
906
|
#pragma mark - UITextViewDelegate (Link Interaction)
|
|
840
907
|
|
|
841
908
|
#if !TARGET_OS_OSX
|
|
909
|
+
// Attachments other than images (inline math) are text, not items: without
|
|
910
|
+
// this a long press on one in an unfocused text view starts UIKit's text item
|
|
911
|
+
// interaction, which presents nothing and leaves the view unable to select.
|
|
912
|
+
- (BOOL)textView:(UITextView *)textView
|
|
913
|
+
shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment
|
|
914
|
+
inRange:(NSRange)characterRange
|
|
915
|
+
interaction:(UITextItemInteraction)interaction
|
|
916
|
+
{
|
|
917
|
+
if ([textAttachment isKindOfClass:[ENRMImageAttachment class]]) {
|
|
918
|
+
return YES;
|
|
919
|
+
}
|
|
920
|
+
// A long press selects the attachment like a word, as it does once the view is focused.
|
|
921
|
+
if (interaction == UITextItemInteractionPresentActions) {
|
|
922
|
+
__weak UITextView *weakTextView = textView;
|
|
923
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
924
|
+
UITextView *strongTextView = weakTextView;
|
|
925
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
[strongTextView becomeFirstResponder];
|
|
929
|
+
strongTextView.selectedRange = characterRange;
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
return NO;
|
|
933
|
+
}
|
|
934
|
+
|
|
842
935
|
- (BOOL)textView:(ENRMPlatformTextView *)textView
|
|
843
936
|
shouldInteractWithURL:(NSURL *)URL
|
|
844
937
|
inRange:(NSRange)characterRange
|
|
@@ -858,6 +951,13 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
858
951
|
return NO;
|
|
859
952
|
}
|
|
860
953
|
|
|
954
|
+
#pragma mark - UITextViewDelegate (Selection)
|
|
955
|
+
|
|
956
|
+
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
957
|
+
{
|
|
958
|
+
[_selectionReporter selectionChanged:textView.selectedRange.length > 0];
|
|
959
|
+
}
|
|
960
|
+
|
|
861
961
|
#pragma mark - UITextViewDelegate (Edit Menu)
|
|
862
962
|
|
|
863
963
|
// TODO: Remove API_AVAILABLE(ios(16.0)) guard when the minimum iOS deployment target in RN is bumped to 16.
|
|
@@ -865,8 +965,10 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
865
965
|
editMenuForTextInRange:(NSRange)range
|
|
866
966
|
suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0))
|
|
867
967
|
{
|
|
968
|
+
// An empty menu presents nothing; nil would make UIKit show its default menu
|
|
969
|
+
// (the selection and handles stay either way).
|
|
868
970
|
if (_contextMenuHidden) {
|
|
869
|
-
return
|
|
971
|
+
return [UIMenu menuWithChildren:@[]];
|
|
870
972
|
}
|
|
871
973
|
|
|
872
974
|
__weak EnrichedMarkdownText *weakSelf = self;
|
|
@@ -55,6 +55,43 @@ fragmentsObject.setProperty(runtime, "height", fragmentsValue.height);
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
void EnrichedMarkdownEventEmitter::onSelectionChange(OnSelectionChange event) const {
|
|
59
|
+
dispatchEvent("selectionChange", [event=std::move(event)](jsi::Runtime &runtime) {
|
|
60
|
+
auto payload = jsi::Object(runtime);
|
|
61
|
+
payload.setProperty(runtime, "active", event.active);
|
|
62
|
+
payload.setProperty(runtime, "source", event.source);
|
|
63
|
+
payload.setProperty(runtime, "text", event.text);
|
|
64
|
+
payload.setProperty(runtime, "markdown", event.markdown);
|
|
65
|
+
payload.setProperty(runtime, "whole", event.whole);
|
|
66
|
+
{
|
|
67
|
+
auto rect = jsi::Object(runtime);
|
|
68
|
+
rect.setProperty(runtime, "x", event.rect.x);
|
|
69
|
+
rect.setProperty(runtime, "y", event.rect.y);
|
|
70
|
+
rect.setProperty(runtime, "width", event.rect.width);
|
|
71
|
+
rect.setProperty(runtime, "height", event.rect.height);
|
|
72
|
+
payload.setProperty(runtime, "rect", rect);
|
|
73
|
+
}
|
|
74
|
+
{
|
|
75
|
+
auto startRect = jsi::Object(runtime);
|
|
76
|
+
startRect.setProperty(runtime, "x", event.startRect.x);
|
|
77
|
+
startRect.setProperty(runtime, "y", event.startRect.y);
|
|
78
|
+
startRect.setProperty(runtime, "width", event.startRect.width);
|
|
79
|
+
startRect.setProperty(runtime, "height", event.startRect.height);
|
|
80
|
+
payload.setProperty(runtime, "startRect", startRect);
|
|
81
|
+
}
|
|
82
|
+
{
|
|
83
|
+
auto endRect = jsi::Object(runtime);
|
|
84
|
+
endRect.setProperty(runtime, "x", event.endRect.x);
|
|
85
|
+
endRect.setProperty(runtime, "y", event.endRect.y);
|
|
86
|
+
endRect.setProperty(runtime, "width", event.endRect.width);
|
|
87
|
+
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
88
|
+
payload.setProperty(runtime, "endRect", endRect);
|
|
89
|
+
}
|
|
90
|
+
return payload;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
58
95
|
void EnrichedMarkdownEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const {
|
|
59
96
|
dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) {
|
|
60
97
|
auto payload = jsi::Object(runtime);
|
|
@@ -418,6 +455,43 @@ fragmentsObject.setProperty(runtime, "height", fragmentsValue.height);
|
|
|
418
455
|
}
|
|
419
456
|
|
|
420
457
|
|
|
458
|
+
void EnrichedMarkdownTextEventEmitter::onSelectionChange(OnSelectionChange event) const {
|
|
459
|
+
dispatchEvent("selectionChange", [event=std::move(event)](jsi::Runtime &runtime) {
|
|
460
|
+
auto payload = jsi::Object(runtime);
|
|
461
|
+
payload.setProperty(runtime, "active", event.active);
|
|
462
|
+
payload.setProperty(runtime, "source", event.source);
|
|
463
|
+
payload.setProperty(runtime, "text", event.text);
|
|
464
|
+
payload.setProperty(runtime, "markdown", event.markdown);
|
|
465
|
+
payload.setProperty(runtime, "whole", event.whole);
|
|
466
|
+
{
|
|
467
|
+
auto rect = jsi::Object(runtime);
|
|
468
|
+
rect.setProperty(runtime, "x", event.rect.x);
|
|
469
|
+
rect.setProperty(runtime, "y", event.rect.y);
|
|
470
|
+
rect.setProperty(runtime, "width", event.rect.width);
|
|
471
|
+
rect.setProperty(runtime, "height", event.rect.height);
|
|
472
|
+
payload.setProperty(runtime, "rect", rect);
|
|
473
|
+
}
|
|
474
|
+
{
|
|
475
|
+
auto startRect = jsi::Object(runtime);
|
|
476
|
+
startRect.setProperty(runtime, "x", event.startRect.x);
|
|
477
|
+
startRect.setProperty(runtime, "y", event.startRect.y);
|
|
478
|
+
startRect.setProperty(runtime, "width", event.startRect.width);
|
|
479
|
+
startRect.setProperty(runtime, "height", event.startRect.height);
|
|
480
|
+
payload.setProperty(runtime, "startRect", startRect);
|
|
481
|
+
}
|
|
482
|
+
{
|
|
483
|
+
auto endRect = jsi::Object(runtime);
|
|
484
|
+
endRect.setProperty(runtime, "x", event.endRect.x);
|
|
485
|
+
endRect.setProperty(runtime, "y", event.endRect.y);
|
|
486
|
+
endRect.setProperty(runtime, "width", event.endRect.width);
|
|
487
|
+
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
488
|
+
payload.setProperty(runtime, "endRect", endRect);
|
|
489
|
+
}
|
|
490
|
+
return payload;
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
|
|
421
495
|
void EnrichedMarkdownTextEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const {
|
|
422
496
|
dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) {
|
|
423
497
|
auto payload = jsi::Object(runtime);
|
|
@@ -39,6 +39,38 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
|
|
|
39
39
|
std::vector<OnLinkLayoutFragments> fragments;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
struct OnSelectionChangeRect {
|
|
43
|
+
double x;
|
|
44
|
+
double y;
|
|
45
|
+
double width;
|
|
46
|
+
double height;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
struct OnSelectionChangeStartRect {
|
|
50
|
+
double x;
|
|
51
|
+
double y;
|
|
52
|
+
double width;
|
|
53
|
+
double height;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
struct OnSelectionChangeEndRect {
|
|
57
|
+
double x;
|
|
58
|
+
double y;
|
|
59
|
+
double width;
|
|
60
|
+
double height;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
struct OnSelectionChange {
|
|
64
|
+
bool active;
|
|
65
|
+
std::string source;
|
|
66
|
+
std::string text;
|
|
67
|
+
std::string markdown;
|
|
68
|
+
bool whole;
|
|
69
|
+
OnSelectionChangeRect rect;
|
|
70
|
+
OnSelectionChangeStartRect startRect;
|
|
71
|
+
OnSelectionChangeEndRect endRect;
|
|
72
|
+
};
|
|
73
|
+
|
|
42
74
|
struct OnTaskListItemPress {
|
|
43
75
|
int index;
|
|
44
76
|
bool checked;
|
|
@@ -69,6 +101,8 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
|
|
|
69
101
|
|
|
70
102
|
void onLinkLayout(OnLinkLayout value) const;
|
|
71
103
|
|
|
104
|
+
void onSelectionChange(OnSelectionChange value) const;
|
|
105
|
+
|
|
72
106
|
void onTaskListItemPress(OnTaskListItemPress value) const;
|
|
73
107
|
|
|
74
108
|
void onCopyPress(OnCopyPress value) const;
|
|
@@ -331,6 +365,38 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
|
|
|
331
365
|
std::vector<OnLinkLayoutFragments> fragments;
|
|
332
366
|
};
|
|
333
367
|
|
|
368
|
+
struct OnSelectionChangeRect {
|
|
369
|
+
double x;
|
|
370
|
+
double y;
|
|
371
|
+
double width;
|
|
372
|
+
double height;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
struct OnSelectionChangeStartRect {
|
|
376
|
+
double x;
|
|
377
|
+
double y;
|
|
378
|
+
double width;
|
|
379
|
+
double height;
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
struct OnSelectionChangeEndRect {
|
|
383
|
+
double x;
|
|
384
|
+
double y;
|
|
385
|
+
double width;
|
|
386
|
+
double height;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
struct OnSelectionChange {
|
|
390
|
+
bool active;
|
|
391
|
+
std::string source;
|
|
392
|
+
std::string text;
|
|
393
|
+
std::string markdown;
|
|
394
|
+
bool whole;
|
|
395
|
+
OnSelectionChangeRect rect;
|
|
396
|
+
OnSelectionChangeStartRect startRect;
|
|
397
|
+
OnSelectionChangeEndRect endRect;
|
|
398
|
+
};
|
|
399
|
+
|
|
334
400
|
struct OnTaskListItemPress {
|
|
335
401
|
int index;
|
|
336
402
|
bool checked;
|
|
@@ -361,6 +427,8 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
|
|
|
361
427
|
|
|
362
428
|
void onLinkLayout(OnLinkLayout value) const;
|
|
363
429
|
|
|
430
|
+
void onSelectionChange(OnSelectionChange value) const;
|
|
431
|
+
|
|
364
432
|
void onTaskListItemPress(OnTaskListItemPress value) const;
|
|
365
433
|
|
|
366
434
|
void onCopyPress(OnCopyPress value) const;
|
|
@@ -22,6 +22,7 @@ EnrichedMarkdownProps::EnrichedMarkdownProps(
|
|
|
22
22
|
markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})),
|
|
23
23
|
markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})),
|
|
24
24
|
emitLinkLayout(convertRawProp(context, rawProps, "emitLinkLayout", sourceProps.emitLinkLayout, {false})),
|
|
25
|
+
emitSelectionChange(convertRawProp(context, rawProps, "emitSelectionChange", sourceProps.emitSelectionChange, {false})),
|
|
25
26
|
enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
|
|
26
27
|
enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
|
|
27
28
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
@@ -71,6 +72,10 @@ folly::dynamic EnrichedMarkdownProps::getDiffProps(
|
|
|
71
72
|
result["emitLinkLayout"] = emitLinkLayout;
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
if (emitSelectionChange != oldProps->emitSelectionChange) {
|
|
76
|
+
result["emitSelectionChange"] = emitSelectionChange;
|
|
77
|
+
}
|
|
78
|
+
|
|
74
79
|
if (enableTaskListItemToggle != oldProps->enableTaskListItemToggle) {
|
|
75
80
|
result["enableTaskListItemToggle"] = enableTaskListItemToggle;
|
|
76
81
|
}
|
|
@@ -310,6 +315,7 @@ EnrichedMarkdownTextProps::EnrichedMarkdownTextProps(
|
|
|
310
315
|
markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})),
|
|
311
316
|
markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})),
|
|
312
317
|
emitLinkLayout(convertRawProp(context, rawProps, "emitLinkLayout", sourceProps.emitLinkLayout, {false})),
|
|
318
|
+
emitSelectionChange(convertRawProp(context, rawProps, "emitSelectionChange", sourceProps.emitSelectionChange, {false})),
|
|
313
319
|
enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
|
|
314
320
|
enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
|
|
315
321
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
@@ -359,6 +365,10 @@ folly::dynamic EnrichedMarkdownTextProps::getDiffProps(
|
|
|
359
365
|
result["emitLinkLayout"] = emitLinkLayout;
|
|
360
366
|
}
|
|
361
367
|
|
|
368
|
+
if (emitSelectionChange != oldProps->emitSelectionChange) {
|
|
369
|
+
result["emitSelectionChange"] = emitSelectionChange;
|
|
370
|
+
}
|
|
371
|
+
|
|
362
372
|
if (enableTaskListItemToggle != oldProps->enableTaskListItemToggle) {
|
|
363
373
|
result["enableTaskListItemToggle"] = enableTaskListItemToggle;
|
|
364
374
|
}
|
|
@@ -2887,6 +2887,7 @@ class EnrichedMarkdownProps final : public ViewProps {
|
|
|
2887
2887
|
std::string markdown{};
|
|
2888
2888
|
EnrichedMarkdownMarkdownStyleStruct markdownStyle{};
|
|
2889
2889
|
bool emitLinkLayout{false};
|
|
2890
|
+
bool emitSelectionChange{false};
|
|
2890
2891
|
bool enableTaskListItemToggle{true};
|
|
2891
2892
|
bool enableLinkPreview{true};
|
|
2892
2893
|
bool selectable{false};
|
|
@@ -6931,6 +6932,7 @@ class EnrichedMarkdownTextProps final : public ViewProps {
|
|
|
6931
6932
|
std::string markdown{};
|
|
6932
6933
|
EnrichedMarkdownTextMarkdownStyleStruct markdownStyle{};
|
|
6933
6934
|
bool emitLinkLayout{false};
|
|
6935
|
+
bool emitSelectionChange{false};
|
|
6934
6936
|
bool enableTaskListItemToggle{true};
|
|
6935
6937
|
bool enableLinkPreview{true};
|
|
6936
6938
|
bool selectable{false};
|