react-native-enriched-markdown-scaffold 1.0.2-scaffold.4 → 1.0.2-scaffold.6
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 +15 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +15 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +3 -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 +20 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +4 -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 +22 -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 +22 -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 +68 -0
- package/docs/WEB.md +1 -0
- package/ios/EnrichedMarkdown.mm +188 -2
- package/ios/EnrichedMarkdownText.mm +117 -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 +20 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +4 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +50 -2
- package/ios/utils/ENRMLinkChip.m +38 -20
- 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/EditMenuUtils.h +3 -0
- package/ios/utils/EditMenuUtils.m +116 -0
- 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 +70 -1
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +70 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/jest/index.js +14 -0
- package/lib/module/jest/index.js.map +1 -1
- package/lib/module/native/EnrichedMarkdownText.js +46 -4
- package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +63 -2
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +63 -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 +46 -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 +70 -1
- package/src/EnrichedMarkdownTextNativeComponent.ts +70 -1
- package/src/index.tsx +3 -0
- package/src/jest/index.tsx +22 -1
- package/src/native/EnrichedMarkdownText.tsx +87 -9
- package/src/types/MarkdownTextProps.ts +53 -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"
|
|
@@ -106,6 +107,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
106
107
|
BOOL _allowTrailingMargin;
|
|
107
108
|
BOOL _selectable;
|
|
108
109
|
BOOL _enableLinkPreview;
|
|
110
|
+
BOOL _linkLongPressSelects;
|
|
109
111
|
BOOL _enableTaskListItemToggle;
|
|
110
112
|
BOOL _contextMenuHidden;
|
|
111
113
|
BOOL _streamingAnimation;
|
|
@@ -128,6 +130,15 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
128
130
|
BOOL _emitLinkLayout;
|
|
129
131
|
NSArray<NSDictionary *> *_lastLinkLayout;
|
|
130
132
|
|
|
133
|
+
ENRMSelectionChangeReporter *_selectionReporter;
|
|
134
|
+
// At most one segment holds a selection; a new one clears the previous.
|
|
135
|
+
__weak ENRMPlatformTextView *_selectionOwner;
|
|
136
|
+
// A block long-pressed while contextMenuHidden is on, reported as the selection.
|
|
137
|
+
__weak RCTUIView *_activeBlockView;
|
|
138
|
+
NSString *_activeBlockSource;
|
|
139
|
+
NSString *_activeBlockMarkdown;
|
|
140
|
+
NSString *_activeBlockText;
|
|
141
|
+
|
|
131
142
|
NSLineBreakStrategy _lineBreakStrategy;
|
|
132
143
|
|
|
133
144
|
ENRMWritingDirectionMode _writingDirectionMode;
|
|
@@ -199,10 +210,117 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
199
210
|
[strongSelf renderMarkdownContent:strongSelf->_cachedMarkdown];
|
|
200
211
|
}
|
|
201
212
|
};
|
|
213
|
+
|
|
214
|
+
_selectionReporter = [[ENRMSelectionChangeReporter alloc]
|
|
215
|
+
initWithSnapshot:^NSDictionary * {
|
|
216
|
+
EnrichedMarkdown *strongSelf = weakSelf;
|
|
217
|
+
return strongSelf ? [strongSelf selectionPayload] : ENRMInactiveSelectionPayload();
|
|
218
|
+
}
|
|
219
|
+
emit:^(NSDictionary *payload) {
|
|
220
|
+
EnrichedMarkdown *strongSelf = weakSelf;
|
|
221
|
+
if (!strongSelf)
|
|
222
|
+
return;
|
|
223
|
+
auto emitter = std::static_pointer_cast<EnrichedMarkdownEventEmitter const>(strongSelf->_eventEmitter);
|
|
224
|
+
if (emitter)
|
|
225
|
+
emitter->onSelectionChange(
|
|
226
|
+
ENRMSelectionChangeEventFromPayload<EnrichedMarkdownEventEmitter::OnSelectionChange>(payload));
|
|
227
|
+
}];
|
|
202
228
|
}
|
|
203
229
|
return self;
|
|
204
230
|
}
|
|
205
231
|
|
|
232
|
+
#pragma mark - Selection
|
|
233
|
+
|
|
234
|
+
/// The current selection (or active block) as an `onSelectionChange` payload.
|
|
235
|
+
/// Markdown and `whole` follow the same rules as the intercepted Copy.
|
|
236
|
+
- (NSDictionary *)selectionPayload
|
|
237
|
+
{
|
|
238
|
+
RCTUIView *blockView = _activeBlockView;
|
|
239
|
+
if (blockView != nil) {
|
|
240
|
+
if (blockView.superview != self)
|
|
241
|
+
return ENRMInactiveSelectionPayload();
|
|
242
|
+
return ENRMBlockSelectionPayload(_activeBlockSource, _activeBlockMarkdown, _activeBlockText, blockView.frame);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
#if !TARGET_OS_OSX
|
|
246
|
+
UITextView *owner = _selectionOwner;
|
|
247
|
+
if (owner == nil || ![owner isDescendantOfView:self])
|
|
248
|
+
return ENRMInactiveSelectionPayload();
|
|
249
|
+
NSDictionary *selection = ENRMTextSelectionInTextView(owner, self);
|
|
250
|
+
if (!selection)
|
|
251
|
+
return ENRMInactiveSelectionPayload();
|
|
252
|
+
|
|
253
|
+
NSString *text = selection[ENRMSelectionTextKey];
|
|
254
|
+
// Segments only see their own text, so a selection is the whole component
|
|
255
|
+
// only when it spans the sole segment; the markdown is then the original.
|
|
256
|
+
BOOL whole = [selection[ENRMSelectionFullKey] boolValue] && _segmentViews.count == 1 && _cachedMarkdown.length > 0;
|
|
257
|
+
NSString *markdown =
|
|
258
|
+
whole ? _cachedMarkdown : extractMarkdownFromAttributedString(owner.attributedText, owner.selectedRange);
|
|
259
|
+
NSMutableDictionary *payload = [selection mutableCopy];
|
|
260
|
+
[payload removeObjectForKey:ENRMSelectionFullKey];
|
|
261
|
+
payload[ENRMSelectionActiveKey] = @YES;
|
|
262
|
+
payload[ENRMSelectionSourceKey] = @"selection";
|
|
263
|
+
payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
|
|
264
|
+
payload[ENRMSelectionWholeKey] = @(whole);
|
|
265
|
+
return payload;
|
|
266
|
+
#else
|
|
267
|
+
return ENRMInactiveSelectionPayload();
|
|
268
|
+
#endif
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
- (void)clearActiveBlock
|
|
272
|
+
{
|
|
273
|
+
_activeBlockView = nil;
|
|
274
|
+
_activeBlockSource = nil;
|
|
275
|
+
_activeBlockMarkdown = nil;
|
|
276
|
+
_activeBlockText = nil;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
- (void)clearSegmentSelection:(ENRMPlatformTextView *)textView
|
|
280
|
+
{
|
|
281
|
+
#if !TARGET_OS_OSX
|
|
282
|
+
textView.selectedRange = NSMakeRange(0, 0);
|
|
283
|
+
[textView resignFirstResponder];
|
|
284
|
+
#endif
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
- (void)clearSelection
|
|
288
|
+
{
|
|
289
|
+
ENRMPlatformTextView *owner = _selectionOwner;
|
|
290
|
+
_selectionOwner = nil;
|
|
291
|
+
[self clearActiveBlock];
|
|
292
|
+
if (owner)
|
|
293
|
+
[self clearSegmentSelection:owner];
|
|
294
|
+
[_selectionReporter flushNow];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
|
298
|
+
{
|
|
299
|
+
RCTEnrichedMarkdownHandleCommand(self, commandName, args);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
- (ENRMBlockCopyRequestBlock)blockMenuSuppressedForSource:(NSString *)source view:(RCTUIView *)view
|
|
303
|
+
{
|
|
304
|
+
__weak EnrichedMarkdown *weakSelf = self;
|
|
305
|
+
__weak RCTUIView *weakView = view;
|
|
306
|
+
return ^(NSString *markdown, NSString *text) {
|
|
307
|
+
EnrichedMarkdown *strongSelf = weakSelf;
|
|
308
|
+
RCTUIView *strongView = weakView;
|
|
309
|
+
if (!strongSelf || !strongView || !strongSelf->_selectionReporter.enabled)
|
|
310
|
+
return;
|
|
311
|
+
ENRMPlatformTextView *owner = strongSelf->_selectionOwner;
|
|
312
|
+
strongSelf->_selectionOwner = nil;
|
|
313
|
+
if (owner)
|
|
314
|
+
[strongSelf clearSegmentSelection:owner];
|
|
315
|
+
strongSelf->_activeBlockView = strongView;
|
|
316
|
+
strongSelf->_activeBlockSource = source;
|
|
317
|
+
strongSelf->_activeBlockMarkdown = markdown;
|
|
318
|
+
strongSelf->_activeBlockText = text;
|
|
319
|
+
[strongSelf->_selectionReporter forgetLastReported];
|
|
320
|
+
[strongSelf->_selectionReporter flushNow];
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
206
324
|
- (void)configureSegmentViewRegistry
|
|
207
325
|
{
|
|
208
326
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
@@ -839,6 +957,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
839
957
|
tableView.contextMenuHidden = _contextMenuHidden;
|
|
840
958
|
tableView.menuOptions = [self blockMenuOptions];
|
|
841
959
|
tableView.onCopyRequest = [self blockCopyRequestForSource:@"table"];
|
|
960
|
+
tableView.onMenuSuppressed = [self blockMenuSuppressedForSource:@"table" view:tableView];
|
|
842
961
|
|
|
843
962
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
844
963
|
|
|
@@ -881,6 +1000,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
881
1000
|
mathView.contextMenuHidden = _contextMenuHidden;
|
|
882
1001
|
mathView.menuOptions = [self blockMenuOptions];
|
|
883
1002
|
mathView.onCopyRequest = [self blockCopyRequestForSource:@"math"];
|
|
1003
|
+
mathView.onMenuSuppressed = [self blockMenuSuppressedForSource:@"math" view:mathView];
|
|
884
1004
|
[mathView applyLatex:mathSegment.latex];
|
|
885
1005
|
return mathView;
|
|
886
1006
|
}
|
|
@@ -894,6 +1014,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
894
1014
|
codeBlockView.contextMenuHidden = _contextMenuHidden;
|
|
895
1015
|
codeBlockView.menuOptions = [self blockMenuOptions];
|
|
896
1016
|
codeBlockView.onCopyRequest = [self blockCopyRequestForSource:@"code"];
|
|
1017
|
+
codeBlockView.onMenuSuppressed = [self blockMenuSuppressedForSource:@"code" view:codeBlockView];
|
|
897
1018
|
|
|
898
1019
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
899
1020
|
codeBlockView.onCopyPress = ^(NSString *code, NSString *language) {
|
|
@@ -947,6 +1068,8 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
947
1068
|
[super layoutSubviews];
|
|
948
1069
|
[self computeSegmentLayoutForWidth:self.bounds.size.width applyFrames:YES];
|
|
949
1070
|
[self emitLinkLayoutIfNeeded];
|
|
1071
|
+
// Segments may have moved or been replaced; re-read the selection (deduplicated).
|
|
1072
|
+
[_selectionReporter schedule];
|
|
950
1073
|
}
|
|
951
1074
|
|
|
952
1075
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
@@ -988,6 +1111,8 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
988
1111
|
[self setNeedsLayout];
|
|
989
1112
|
}
|
|
990
1113
|
|
|
1114
|
+
_selectionReporter.enabled = newViewProps.emitSelectionChange;
|
|
1115
|
+
|
|
991
1116
|
for (RCTUIView *segment in _segmentViews) {
|
|
992
1117
|
if ([segment isKindOfClass:[EnrichedMarkdownInternalText class]]) {
|
|
993
1118
|
EnrichedMarkdownInternalText *textSegment = (EnrichedMarkdownInternalText *)segment;
|
|
@@ -1029,6 +1154,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
1029
1154
|
}
|
|
1030
1155
|
|
|
1031
1156
|
_enableLinkPreview = newViewProps.enableLinkPreview;
|
|
1157
|
+
_linkLongPressSelects = newViewProps.linkLongPressSelects;
|
|
1032
1158
|
_enableTaskListItemToggle = newViewProps.enableTaskListItemToggle;
|
|
1033
1159
|
_contextMenuHidden = newViewProps.contextMenuHidden;
|
|
1034
1160
|
|
|
@@ -1185,6 +1311,9 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
1185
1311
|
_config = nil;
|
|
1186
1312
|
_emitLinkLayout = NO;
|
|
1187
1313
|
_lastLinkLayout = nil;
|
|
1314
|
+
_selectionReporter.enabled = NO;
|
|
1315
|
+
_selectionOwner = nil;
|
|
1316
|
+
[self clearActiveBlock];
|
|
1188
1317
|
_md4cFlags = [EnrichedMarkdown flagsFromProps:resetProps->md4cFlags];
|
|
1189
1318
|
_maxFontSizeMultiplier = 0;
|
|
1190
1319
|
_allowTrailingMargin = NO;
|
|
@@ -1406,14 +1535,34 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1406
1535
|
ENRMHandleTapOnTextView(textView, recognizer, ^(NSString *url) { [self emitLinkPress:url]; });
|
|
1407
1536
|
}
|
|
1408
1537
|
|
|
1538
|
+
#if !TARGET_OS_OSX
|
|
1539
|
+
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
1540
|
+
{
|
|
1541
|
+
ENRMDismissSelectionEditMenuIfMoved(textView);
|
|
1542
|
+
if (textView.selectedRange.length > 0) {
|
|
1543
|
+
// Take ownership first so the previous owner's own "cleared" callback is ignored.
|
|
1544
|
+
ENRMPlatformTextView *previous = _selectionOwner;
|
|
1545
|
+
_selectionOwner = textView;
|
|
1546
|
+
[self clearActiveBlock];
|
|
1547
|
+
if (previous && previous != textView)
|
|
1548
|
+
previous.selectedRange = NSMakeRange(0, 0);
|
|
1549
|
+
[_selectionReporter schedule];
|
|
1550
|
+
} else if (textView == _selectionOwner) {
|
|
1551
|
+
[_selectionReporter selectionChanged:NO];
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
#endif
|
|
1555
|
+
|
|
1409
1556
|
// TODO: Remove API_AVAILABLE(ios(16.0)) guard when the minimum iOS deployment target in RN is bumped to 16.
|
|
1410
1557
|
#if !TARGET_OS_OSX
|
|
1411
1558
|
- (UIMenu *)textView:(UITextView *)textView
|
|
1412
1559
|
editMenuForTextInRange:(NSRange)range
|
|
1413
1560
|
suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0))
|
|
1414
1561
|
{
|
|
1562
|
+
// An empty menu presents nothing; nil would make UIKit show its default menu
|
|
1563
|
+
// (the selection and handles stay either way).
|
|
1415
1564
|
if (_contextMenuHidden) {
|
|
1416
|
-
return
|
|
1565
|
+
return [UIMenu menuWithChildren:@[]];
|
|
1417
1566
|
}
|
|
1418
1567
|
|
|
1419
1568
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
@@ -1448,6 +1597,31 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1448
1597
|
customActions, _selectionMenuConfig, onCopyRequest);
|
|
1449
1598
|
}
|
|
1450
1599
|
|
|
1600
|
+
// Attachments other than images (inline math) are text, not items: without
|
|
1601
|
+
// this a long press on one in an unfocused text view starts UIKit's text item
|
|
1602
|
+
// interaction, which presents nothing and leaves the view unable to select.
|
|
1603
|
+
- (BOOL)textView:(UITextView *)textView
|
|
1604
|
+
shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment
|
|
1605
|
+
inRange:(NSRange)characterRange
|
|
1606
|
+
interaction:(UITextItemInteraction)interaction
|
|
1607
|
+
{
|
|
1608
|
+
if ([textAttachment isKindOfClass:[ENRMImageAttachment class]]) {
|
|
1609
|
+
return YES;
|
|
1610
|
+
}
|
|
1611
|
+
// A long press selects the attachment like a word, as it does once the view is focused.
|
|
1612
|
+
if (interaction == UITextItemInteractionPresentActions) {
|
|
1613
|
+
__weak UITextView *weakTextView = textView;
|
|
1614
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1615
|
+
UITextView *strongTextView = weakTextView;
|
|
1616
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
return NO;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1451
1625
|
- (BOOL)textView:(UITextView *)textView
|
|
1452
1626
|
shouldInteractWithURL:(NSURL *)URL
|
|
1453
1627
|
inRange:(NSRange)characterRange
|
|
@@ -1459,6 +1633,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1459
1633
|
|
|
1460
1634
|
NSString *urlString = linkURLAtRange(textView, characterRange);
|
|
1461
1635
|
|
|
1636
|
+
if (urlString && _linkLongPressSelects) {
|
|
1637
|
+
__weak UITextView *weakTextView = textView;
|
|
1638
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1639
|
+
UITextView *strongTextView = weakTextView;
|
|
1640
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
1644
|
+
});
|
|
1645
|
+
return NO;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1462
1648
|
if (!urlString || _enableLinkPreview) {
|
|
1463
1649
|
return YES;
|
|
1464
1650
|
}
|
|
@@ -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"
|
|
@@ -85,6 +87,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
85
87
|
CGFloat _lastElementMarginBottom;
|
|
86
88
|
BOOL _allowTrailingMargin;
|
|
87
89
|
BOOL _enableLinkPreview;
|
|
90
|
+
BOOL _linkLongPressSelects;
|
|
88
91
|
BOOL _enableTaskListItemToggle;
|
|
89
92
|
BOOL _contextMenuHidden;
|
|
90
93
|
BOOL _streamingAnimation;
|
|
@@ -115,6 +118,8 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
115
118
|
BOOL _emitLinkLayout;
|
|
116
119
|
NSArray<NSDictionary *> *_lastLinkLayout;
|
|
117
120
|
|
|
121
|
+
ENRMSelectionChangeReporter *_selectionReporter;
|
|
122
|
+
|
|
118
123
|
NSLineBreakStrategy _lineBreakStrategy;
|
|
119
124
|
|
|
120
125
|
ENRMWritingDirectionMode _writingDirectionMode;
|
|
@@ -272,11 +277,68 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
272
277
|
};
|
|
273
278
|
|
|
274
279
|
[self setupTextView];
|
|
280
|
+
[self setupSelectionReporter];
|
|
275
281
|
}
|
|
276
282
|
|
|
277
283
|
return self;
|
|
278
284
|
}
|
|
279
285
|
|
|
286
|
+
- (void)setupSelectionReporter
|
|
287
|
+
{
|
|
288
|
+
__weak EnrichedMarkdownText *weakSelf = self;
|
|
289
|
+
_selectionReporter = [[ENRMSelectionChangeReporter alloc]
|
|
290
|
+
initWithSnapshot:^NSDictionary * {
|
|
291
|
+
EnrichedMarkdownText *strongSelf = weakSelf;
|
|
292
|
+
return strongSelf ? [strongSelf selectionPayload] : ENRMInactiveSelectionPayload();
|
|
293
|
+
}
|
|
294
|
+
emit:^(NSDictionary *payload) {
|
|
295
|
+
EnrichedMarkdownText *strongSelf = weakSelf;
|
|
296
|
+
if (!strongSelf)
|
|
297
|
+
return;
|
|
298
|
+
auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(strongSelf->_eventEmitter);
|
|
299
|
+
if (emitter)
|
|
300
|
+
emitter->onSelectionChange(
|
|
301
|
+
ENRMSelectionChangeEventFromPayload<EnrichedMarkdownTextEventEmitter::OnSelectionChange>(payload));
|
|
302
|
+
}];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/// The current selection as an `onSelectionChange` payload. Markdown and
|
|
306
|
+
/// `whole` follow the same rules as the intercepted Copy (`onCopyRequest`).
|
|
307
|
+
- (NSDictionary *)selectionPayload
|
|
308
|
+
{
|
|
309
|
+
#if !TARGET_OS_OSX
|
|
310
|
+
NSDictionary *selection = ENRMTextSelectionInTextView(_textView, self);
|
|
311
|
+
if (!selection)
|
|
312
|
+
return ENRMInactiveSelectionPayload();
|
|
313
|
+
|
|
314
|
+
NSString *text = selection[ENRMSelectionTextKey];
|
|
315
|
+
NSString *markdown = markdownForRange(_textView.attributedText, _textView.selectedRange, _cachedMarkdown);
|
|
316
|
+
NSMutableDictionary *payload = [selection mutableCopy];
|
|
317
|
+
[payload removeObjectForKey:ENRMSelectionFullKey];
|
|
318
|
+
payload[ENRMSelectionActiveKey] = @YES;
|
|
319
|
+
payload[ENRMSelectionSourceKey] = @"selection";
|
|
320
|
+
payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
|
|
321
|
+
payload[ENRMSelectionWholeKey] = @([selection[ENRMSelectionFullKey] boolValue] && _cachedMarkdown.length > 0);
|
|
322
|
+
return payload;
|
|
323
|
+
#else
|
|
324
|
+
return ENRMInactiveSelectionPayload();
|
|
325
|
+
#endif
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
- (void)clearSelection
|
|
329
|
+
{
|
|
330
|
+
#if !TARGET_OS_OSX
|
|
331
|
+
_textView.selectedRange = NSMakeRange(0, 0);
|
|
332
|
+
[_textView resignFirstResponder];
|
|
333
|
+
#endif
|
|
334
|
+
[_selectionReporter flushNow];
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
|
338
|
+
{
|
|
339
|
+
RCTEnrichedMarkdownTextHandleCommand(self, commandName, args);
|
|
340
|
+
}
|
|
341
|
+
|
|
280
342
|
- (void)setupTextView
|
|
281
343
|
{
|
|
282
344
|
#if !TARGET_OS_OSX
|
|
@@ -477,6 +539,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
477
539
|
[self emitLinkLayoutIfNeeded];
|
|
478
540
|
}
|
|
479
541
|
|
|
542
|
+
// New text drops the selection; setting attributedText doesn't call the delegate.
|
|
543
|
+
[_selectionReporter schedule];
|
|
544
|
+
|
|
480
545
|
if (_textView.hidden) {
|
|
481
546
|
dispatch_async(dispatch_get_main_queue(), ^{ self->_textView.hidden = NO; });
|
|
482
547
|
}
|
|
@@ -539,6 +604,8 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
539
604
|
[self emitLinkLayoutIfNeeded];
|
|
540
605
|
}
|
|
541
606
|
|
|
607
|
+
_selectionReporter.enabled = newViewProps.emitSelectionChange;
|
|
608
|
+
|
|
542
609
|
if (_textView.selectable != newViewProps.selectable) {
|
|
543
610
|
_textView.selectable = newViewProps.selectable;
|
|
544
611
|
}
|
|
@@ -587,6 +654,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
587
654
|
}
|
|
588
655
|
|
|
589
656
|
_enableLinkPreview = newViewProps.enableLinkPreview;
|
|
657
|
+
_linkLongPressSelects = newViewProps.linkLongPressSelects;
|
|
590
658
|
_enableTaskListItemToggle = newViewProps.enableTaskListItemToggle;
|
|
591
659
|
_contextMenuHidden = newViewProps.contextMenuHidden;
|
|
592
660
|
|
|
@@ -717,6 +785,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
717
785
|
_spoilerManager = nil;
|
|
718
786
|
_emitLinkLayout = NO;
|
|
719
787
|
_lastLinkLayout = nil;
|
|
788
|
+
_selectionReporter.enabled = NO;
|
|
720
789
|
if (_textView != nil) {
|
|
721
790
|
ENRMSetAttributedText(_textView, [[NSAttributedString alloc] initWithString:@""]);
|
|
722
791
|
_textView.hidden = YES;
|
|
@@ -839,6 +908,31 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
839
908
|
#pragma mark - UITextViewDelegate (Link Interaction)
|
|
840
909
|
|
|
841
910
|
#if !TARGET_OS_OSX
|
|
911
|
+
// Attachments other than images (inline math) are text, not items: without
|
|
912
|
+
// this a long press on one in an unfocused text view starts UIKit's text item
|
|
913
|
+
// interaction, which presents nothing and leaves the view unable to select.
|
|
914
|
+
- (BOOL)textView:(UITextView *)textView
|
|
915
|
+
shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment
|
|
916
|
+
inRange:(NSRange)characterRange
|
|
917
|
+
interaction:(UITextItemInteraction)interaction
|
|
918
|
+
{
|
|
919
|
+
if ([textAttachment isKindOfClass:[ENRMImageAttachment class]]) {
|
|
920
|
+
return YES;
|
|
921
|
+
}
|
|
922
|
+
// A long press selects the attachment like a word, as it does once the view is focused.
|
|
923
|
+
if (interaction == UITextItemInteractionPresentActions) {
|
|
924
|
+
__weak UITextView *weakTextView = textView;
|
|
925
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
926
|
+
UITextView *strongTextView = weakTextView;
|
|
927
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
return NO;
|
|
934
|
+
}
|
|
935
|
+
|
|
842
936
|
- (BOOL)textView:(ENRMPlatformTextView *)textView
|
|
843
937
|
shouldInteractWithURL:(NSURL *)URL
|
|
844
938
|
inRange:(NSRange)characterRange
|
|
@@ -850,6 +944,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
850
944
|
|
|
851
945
|
NSString *urlString = linkURLAtRange(textView, characterRange);
|
|
852
946
|
|
|
947
|
+
if (urlString && _linkLongPressSelects) {
|
|
948
|
+
__weak UITextView *weakTextView = textView;
|
|
949
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
950
|
+
UITextView *strongTextView = weakTextView;
|
|
951
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
955
|
+
});
|
|
956
|
+
return NO;
|
|
957
|
+
}
|
|
958
|
+
|
|
853
959
|
if (!urlString || _enableLinkPreview) {
|
|
854
960
|
return YES;
|
|
855
961
|
}
|
|
@@ -858,6 +964,14 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
858
964
|
return NO;
|
|
859
965
|
}
|
|
860
966
|
|
|
967
|
+
#pragma mark - UITextViewDelegate (Selection)
|
|
968
|
+
|
|
969
|
+
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
970
|
+
{
|
|
971
|
+
ENRMDismissSelectionEditMenuIfMoved(textView);
|
|
972
|
+
[_selectionReporter selectionChanged:textView.selectedRange.length > 0];
|
|
973
|
+
}
|
|
974
|
+
|
|
861
975
|
#pragma mark - UITextViewDelegate (Edit Menu)
|
|
862
976
|
|
|
863
977
|
// TODO: Remove API_AVAILABLE(ios(16.0)) guard when the minimum iOS deployment target in RN is bumped to 16.
|
|
@@ -865,8 +979,10 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
865
979
|
editMenuForTextInRange:(NSRange)range
|
|
866
980
|
suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0))
|
|
867
981
|
{
|
|
982
|
+
// An empty menu presents nothing; nil would make UIKit show its default menu
|
|
983
|
+
// (the selection and handles stay either way).
|
|
868
984
|
if (_contextMenuHidden) {
|
|
869
|
-
return
|
|
985
|
+
return [UIMenu menuWithChildren:@[]];
|
|
870
986
|
}
|
|
871
987
|
|
|
872
988
|
__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;
|