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/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java
CHANGED
|
@@ -35,12 +35,18 @@ public class EnrichedMarkdownManagerDelegate<T extends View, U extends BaseViewM
|
|
|
35
35
|
case "emitLinkLayout":
|
|
36
36
|
mViewManager.setEmitLinkLayout(view, value == null ? false : (boolean) value);
|
|
37
37
|
break;
|
|
38
|
+
case "emitSelectionChange":
|
|
39
|
+
mViewManager.setEmitSelectionChange(view, value == null ? false : (boolean) value);
|
|
40
|
+
break;
|
|
38
41
|
case "enableTaskListItemToggle":
|
|
39
42
|
mViewManager.setEnableTaskListItemToggle(view, value == null ? true : (boolean) value);
|
|
40
43
|
break;
|
|
41
44
|
case "enableLinkPreview":
|
|
42
45
|
mViewManager.setEnableLinkPreview(view, value == null ? true : (boolean) value);
|
|
43
46
|
break;
|
|
47
|
+
case "linkLongPressSelects":
|
|
48
|
+
mViewManager.setLinkLongPressSelects(view, value == null ? false : (boolean) value);
|
|
49
|
+
break;
|
|
44
50
|
case "selectable":
|
|
45
51
|
mViewManager.setSelectable(view, value == null ? false : (boolean) value);
|
|
46
52
|
break;
|
|
@@ -99,4 +105,13 @@ public class EnrichedMarkdownManagerDelegate<T extends View, U extends BaseViewM
|
|
|
99
105
|
super.setProperty(view, propName, value);
|
|
100
106
|
}
|
|
101
107
|
}
|
|
108
|
+
|
|
109
|
+
@Override
|
|
110
|
+
public void receiveCommand(T view, String commandName, ReadableArray args) {
|
|
111
|
+
switch (commandName) {
|
|
112
|
+
case "clearSelection":
|
|
113
|
+
mViewManager.clearSelection(view);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
102
117
|
}
|
package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java
CHANGED
|
@@ -19,8 +19,10 @@ public interface EnrichedMarkdownManagerInterface<T extends View> extends ViewMa
|
|
|
19
19
|
void setMarkdown(T view, @Nullable String value);
|
|
20
20
|
void setMarkdownStyle(T view, @Nullable ReadableMap value);
|
|
21
21
|
void setEmitLinkLayout(T view, boolean value);
|
|
22
|
+
void setEmitSelectionChange(T view, boolean value);
|
|
22
23
|
void setEnableTaskListItemToggle(T view, boolean value);
|
|
23
24
|
void setEnableLinkPreview(T view, boolean value);
|
|
25
|
+
void setLinkLongPressSelects(T view, boolean value);
|
|
24
26
|
void setSelectable(T view, boolean value);
|
|
25
27
|
void setSelectionColor(T view, @Nullable Integer value);
|
|
26
28
|
void setSelectionHandleColor(T view, @Nullable Integer value);
|
|
@@ -39,4 +41,5 @@ public interface EnrichedMarkdownManagerInterface<T extends View> extends ViewMa
|
|
|
39
41
|
void setTextBreakStrategy(T view, @Nullable String value);
|
|
40
42
|
void setLineBreakStrategyIOS(T view, @Nullable String value);
|
|
41
43
|
void setWritingDirection(T view, @Nullable String value);
|
|
44
|
+
void clearSelection(T view);
|
|
42
45
|
}
|
|
@@ -35,12 +35,18 @@ public class EnrichedMarkdownTextManagerDelegate<T extends View, U extends BaseV
|
|
|
35
35
|
case "emitLinkLayout":
|
|
36
36
|
mViewManager.setEmitLinkLayout(view, value == null ? false : (boolean) value);
|
|
37
37
|
break;
|
|
38
|
+
case "emitSelectionChange":
|
|
39
|
+
mViewManager.setEmitSelectionChange(view, value == null ? false : (boolean) value);
|
|
40
|
+
break;
|
|
38
41
|
case "enableTaskListItemToggle":
|
|
39
42
|
mViewManager.setEnableTaskListItemToggle(view, value == null ? true : (boolean) value);
|
|
40
43
|
break;
|
|
41
44
|
case "enableLinkPreview":
|
|
42
45
|
mViewManager.setEnableLinkPreview(view, value == null ? true : (boolean) value);
|
|
43
46
|
break;
|
|
47
|
+
case "linkLongPressSelects":
|
|
48
|
+
mViewManager.setLinkLongPressSelects(view, value == null ? false : (boolean) value);
|
|
49
|
+
break;
|
|
44
50
|
case "selectable":
|
|
45
51
|
mViewManager.setSelectable(view, value == null ? false : (boolean) value);
|
|
46
52
|
break;
|
|
@@ -99,4 +105,13 @@ public class EnrichedMarkdownTextManagerDelegate<T extends View, U extends BaseV
|
|
|
99
105
|
super.setProperty(view, propName, value);
|
|
100
106
|
}
|
|
101
107
|
}
|
|
108
|
+
|
|
109
|
+
@Override
|
|
110
|
+
public void receiveCommand(T view, String commandName, ReadableArray args) {
|
|
111
|
+
switch (commandName) {
|
|
112
|
+
case "clearSelection":
|
|
113
|
+
mViewManager.clearSelection(view);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
102
117
|
}
|
|
@@ -19,8 +19,10 @@ public interface EnrichedMarkdownTextManagerInterface<T extends View> extends Vi
|
|
|
19
19
|
void setMarkdown(T view, @Nullable String value);
|
|
20
20
|
void setMarkdownStyle(T view, @Nullable ReadableMap value);
|
|
21
21
|
void setEmitLinkLayout(T view, boolean value);
|
|
22
|
+
void setEmitSelectionChange(T view, boolean value);
|
|
22
23
|
void setEnableTaskListItemToggle(T view, boolean value);
|
|
23
24
|
void setEnableLinkPreview(T view, boolean value);
|
|
25
|
+
void setLinkLongPressSelects(T view, boolean value);
|
|
24
26
|
void setSelectable(T view, boolean value);
|
|
25
27
|
void setSelectionColor(T view, @Nullable Integer value);
|
|
26
28
|
void setSelectionHandleColor(T view, @Nullable Integer value);
|
|
@@ -39,4 +41,5 @@ public interface EnrichedMarkdownTextManagerInterface<T extends View> extends Vi
|
|
|
39
41
|
void setTextBreakStrategy(T view, @Nullable String value);
|
|
40
42
|
void setLineBreakStrategyIOS(T view, @Nullable String value);
|
|
41
43
|
void setWritingDirection(T view, @Nullable String value);
|
|
44
|
+
void clearSelection(T view);
|
|
42
45
|
}
|
package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp
CHANGED
|
@@ -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);
|
package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h
CHANGED
|
@@ -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,8 +22,10 @@ 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})),
|
|
28
|
+
linkLongPressSelects(convertRawProp(context, rawProps, "linkLongPressSelects", sourceProps.linkLongPressSelects, {false})),
|
|
27
29
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
28
30
|
selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
|
|
29
31
|
selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})),
|
|
@@ -71,6 +73,10 @@ folly::dynamic EnrichedMarkdownProps::getDiffProps(
|
|
|
71
73
|
result["emitLinkLayout"] = emitLinkLayout;
|
|
72
74
|
}
|
|
73
75
|
|
|
76
|
+
if (emitSelectionChange != oldProps->emitSelectionChange) {
|
|
77
|
+
result["emitSelectionChange"] = emitSelectionChange;
|
|
78
|
+
}
|
|
79
|
+
|
|
74
80
|
if (enableTaskListItemToggle != oldProps->enableTaskListItemToggle) {
|
|
75
81
|
result["enableTaskListItemToggle"] = enableTaskListItemToggle;
|
|
76
82
|
}
|
|
@@ -79,6 +85,10 @@ folly::dynamic EnrichedMarkdownProps::getDiffProps(
|
|
|
79
85
|
result["enableLinkPreview"] = enableLinkPreview;
|
|
80
86
|
}
|
|
81
87
|
|
|
88
|
+
if (linkLongPressSelects != oldProps->linkLongPressSelects) {
|
|
89
|
+
result["linkLongPressSelects"] = linkLongPressSelects;
|
|
90
|
+
}
|
|
91
|
+
|
|
82
92
|
if (selectable != oldProps->selectable) {
|
|
83
93
|
result["selectable"] = selectable;
|
|
84
94
|
}
|
|
@@ -310,8 +320,10 @@ EnrichedMarkdownTextProps::EnrichedMarkdownTextProps(
|
|
|
310
320
|
markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})),
|
|
311
321
|
markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})),
|
|
312
322
|
emitLinkLayout(convertRawProp(context, rawProps, "emitLinkLayout", sourceProps.emitLinkLayout, {false})),
|
|
323
|
+
emitSelectionChange(convertRawProp(context, rawProps, "emitSelectionChange", sourceProps.emitSelectionChange, {false})),
|
|
313
324
|
enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
|
|
314
325
|
enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
|
|
326
|
+
linkLongPressSelects(convertRawProp(context, rawProps, "linkLongPressSelects", sourceProps.linkLongPressSelects, {false})),
|
|
315
327
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
316
328
|
selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
|
|
317
329
|
selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})),
|
|
@@ -359,6 +371,10 @@ folly::dynamic EnrichedMarkdownTextProps::getDiffProps(
|
|
|
359
371
|
result["emitLinkLayout"] = emitLinkLayout;
|
|
360
372
|
}
|
|
361
373
|
|
|
374
|
+
if (emitSelectionChange != oldProps->emitSelectionChange) {
|
|
375
|
+
result["emitSelectionChange"] = emitSelectionChange;
|
|
376
|
+
}
|
|
377
|
+
|
|
362
378
|
if (enableTaskListItemToggle != oldProps->enableTaskListItemToggle) {
|
|
363
379
|
result["enableTaskListItemToggle"] = enableTaskListItemToggle;
|
|
364
380
|
}
|
|
@@ -367,6 +383,10 @@ folly::dynamic EnrichedMarkdownTextProps::getDiffProps(
|
|
|
367
383
|
result["enableLinkPreview"] = enableLinkPreview;
|
|
368
384
|
}
|
|
369
385
|
|
|
386
|
+
if (linkLongPressSelects != oldProps->linkLongPressSelects) {
|
|
387
|
+
result["linkLongPressSelects"] = linkLongPressSelects;
|
|
388
|
+
}
|
|
389
|
+
|
|
370
390
|
if (selectable != oldProps->selectable) {
|
|
371
391
|
result["selectable"] = selectable;
|
|
372
392
|
}
|
|
@@ -2887,8 +2887,10 @@ 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};
|
|
2893
|
+
bool linkLongPressSelects{false};
|
|
2892
2894
|
bool selectable{false};
|
|
2893
2895
|
SharedColor selectionColor{};
|
|
2894
2896
|
SharedColor selectionHandleColor{};
|
|
@@ -6931,8 +6933,10 @@ class EnrichedMarkdownTextProps final : public ViewProps {
|
|
|
6931
6933
|
std::string markdown{};
|
|
6932
6934
|
EnrichedMarkdownTextMarkdownStyleStruct markdownStyle{};
|
|
6933
6935
|
bool emitLinkLayout{false};
|
|
6936
|
+
bool emitSelectionChange{false};
|
|
6934
6937
|
bool enableTaskListItemToggle{true};
|
|
6935
6938
|
bool enableLinkPreview{true};
|
|
6939
|
+
bool linkLongPressSelects{false};
|
|
6936
6940
|
bool selectable{false};
|
|
6937
6941
|
SharedColor selectionColor{};
|
|
6938
6942
|
SharedColor selectionHandleColor{};
|
|
@@ -26,13 +26,18 @@ import com.swmansion.enriched.markdown.utils.common.SegmentReconciler
|
|
|
26
26
|
import com.swmansion.enriched.markdown.utils.common.StreamingMarkdownFilter
|
|
27
27
|
import com.swmansion.enriched.markdown.utils.common.TableStreamingMode
|
|
28
28
|
import com.swmansion.enriched.markdown.utils.common.emitLinkLayout
|
|
29
|
+
import com.swmansion.enriched.markdown.utils.common.emitSelectionChange
|
|
29
30
|
import com.swmansion.enriched.markdown.utils.common.isReducedMotionEnabled
|
|
30
31
|
import com.swmansion.enriched.markdown.utils.common.splitASTIntoSegments
|
|
31
32
|
import com.swmansion.enriched.markdown.utils.text.TailFadeInAnimator
|
|
32
33
|
import com.swmansion.enriched.markdown.utils.text.view.LinkLayoutCollector
|
|
33
34
|
import com.swmansion.enriched.markdown.utils.text.view.LinkLayoutFragment
|
|
35
|
+
import com.swmansion.enriched.markdown.utils.text.view.SelectionChangeReporter
|
|
34
36
|
import com.swmansion.enriched.markdown.utils.text.view.SelectionMenuConfig
|
|
37
|
+
import com.swmansion.enriched.markdown.utils.text.view.SelectionRect
|
|
38
|
+
import com.swmansion.enriched.markdown.utils.text.view.SelectionSnapshot
|
|
35
39
|
import com.swmansion.enriched.markdown.utils.text.view.applySelectionColors
|
|
40
|
+
import com.swmansion.enriched.markdown.utils.text.view.currentTextSelection
|
|
36
41
|
import com.swmansion.enriched.markdown.views.BlockMenuOptions
|
|
37
42
|
import com.swmansion.enriched.markdown.views.BlockSegmentView
|
|
38
43
|
import com.swmansion.enriched.markdown.views.CodeBlockContainerView
|
|
@@ -105,6 +110,21 @@ class EnrichedMarkdown
|
|
|
105
110
|
private var linkLayoutEnabled = false
|
|
106
111
|
private var lastLinkLayout: List<LinkLayoutFragment>? = null
|
|
107
112
|
|
|
113
|
+
// At most one segment holds a selection; a new one clears the previous.
|
|
114
|
+
private var selectionOwner: EnrichedMarkdownInternalText? = null
|
|
115
|
+
|
|
116
|
+
// A block long-pressed while contextMenuHidden is on, reported as the selection.
|
|
117
|
+
private class ActiveBlock(
|
|
118
|
+
val view: View,
|
|
119
|
+
val source: String,
|
|
120
|
+
val markdown: String,
|
|
121
|
+
val text: String,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
private var activeBlock: ActiveBlock? = null
|
|
125
|
+
private val selectionReporter =
|
|
126
|
+
SelectionChangeReporter(this, ::selectionSnapshot) { snapshot -> emitSelectionChange(this, snapshot) }
|
|
127
|
+
|
|
108
128
|
private var onLinkPressCallback: ((String) -> Unit)? = null
|
|
109
129
|
private var onLinkLongPressCallback: ((String) -> Unit)? = null
|
|
110
130
|
private var onTaskListItemPressCallback: ((Int, Boolean, String) -> Unit)? = null
|
|
@@ -398,6 +418,78 @@ class EnrichedMarkdown
|
|
|
398
418
|
onContextMenuItemPressCallback?.invoke(itemText, selectedText, selectionStart, selectionEnd)
|
|
399
419
|
}
|
|
400
420
|
|
|
421
|
+
fun setEmitSelectionChange(enabled: Boolean) {
|
|
422
|
+
selectionReporter.enabled = enabled
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Clears the selection of every segment (and any active block) and reports `active: false`. */
|
|
426
|
+
fun clearSelection() {
|
|
427
|
+
val owner = selectionOwner
|
|
428
|
+
selectionOwner = null
|
|
429
|
+
activeBlock = null
|
|
430
|
+
owner?.clearSelection()
|
|
431
|
+
selectionReporter.flushNow()
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private fun onSegmentSelectionChanged(
|
|
435
|
+
view: EnrichedMarkdownInternalText,
|
|
436
|
+
hasSelection: Boolean,
|
|
437
|
+
) {
|
|
438
|
+
if (hasSelection) {
|
|
439
|
+
// Take ownership first so the previous owner's own "cleared" callback is ignored.
|
|
440
|
+
val previous = selectionOwner
|
|
441
|
+
selectionOwner = view
|
|
442
|
+
activeBlock = null
|
|
443
|
+
if (previous !== view) previous?.clearSelection()
|
|
444
|
+
selectionReporter.schedule()
|
|
445
|
+
} else if (selectionOwner === view) {
|
|
446
|
+
selectionReporter.onSelectionChanged(false)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private fun onBlockMenuSuppressed(
|
|
451
|
+
view: View,
|
|
452
|
+
source: String,
|
|
453
|
+
markdown: String,
|
|
454
|
+
text: String,
|
|
455
|
+
) {
|
|
456
|
+
if (!selectionReporter.enabled) return
|
|
457
|
+
val previous = selectionOwner
|
|
458
|
+
selectionOwner = null
|
|
459
|
+
previous?.clearSelection()
|
|
460
|
+
activeBlock = ActiveBlock(view, source, markdown, text)
|
|
461
|
+
selectionReporter.forgetLastReported()
|
|
462
|
+
selectionReporter.flushNow()
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
private fun selectionSnapshot(): SelectionSnapshot {
|
|
466
|
+
activeBlock?.let { block ->
|
|
467
|
+
if (block.view.parent !== this) return SelectionSnapshot.INACTIVE
|
|
468
|
+
val rect =
|
|
469
|
+
SelectionRect.fromPx(
|
|
470
|
+
block.view.left.toFloat(),
|
|
471
|
+
block.view.top.toFloat(),
|
|
472
|
+
block.view.right.toFloat(),
|
|
473
|
+
block.view.bottom.toFloat(),
|
|
474
|
+
)
|
|
475
|
+
return SelectionSnapshot.block(block.source, block.markdown, block.text, rect)
|
|
476
|
+
}
|
|
477
|
+
val owner = selectionOwner?.takeIf { it.parent === this } ?: return SelectionSnapshot.INACTIVE
|
|
478
|
+
val selection = owner.currentTextSelection(owner.left, owner.top) ?: return SelectionSnapshot.INACTIVE
|
|
479
|
+
// Same rule as forwardSegmentCopyRequest.
|
|
480
|
+
val whole = selection.fullSelection && segmentViews.size == 1 && currentMarkdown.isNotEmpty()
|
|
481
|
+
return SelectionSnapshot(
|
|
482
|
+
active = true,
|
|
483
|
+
source = "selection",
|
|
484
|
+
text = selection.text,
|
|
485
|
+
markdown = if (whole) currentMarkdown else selection.markdown,
|
|
486
|
+
whole = whole,
|
|
487
|
+
rect = selection.rect,
|
|
488
|
+
startRect = selection.startRect,
|
|
489
|
+
endRect = selection.endRect,
|
|
490
|
+
)
|
|
491
|
+
}
|
|
492
|
+
|
|
401
493
|
private fun recreateStyleConfig() {
|
|
402
494
|
markdownStyleMap?.let {
|
|
403
495
|
markdownStyle =
|
|
@@ -498,6 +590,9 @@ class EnrichedMarkdown
|
|
|
498
590
|
segmentSignatures.clear()
|
|
499
591
|
segmentSignatures.addAll(result.signatures)
|
|
500
592
|
|
|
593
|
+
if (selectionOwner?.let { owner -> segmentViews.none { it === owner } } == true) selectionOwner = null
|
|
594
|
+
if (activeBlock?.let { block -> segmentViews.none { it === block.view } } == true) activeBlock = null
|
|
595
|
+
|
|
501
596
|
// A just-closed block has unchanged content, so the reconciler reuses it
|
|
502
597
|
// without an update; sync pending here to trigger its deferred highlight.
|
|
503
598
|
segmentViews.forEachIndexed { index, view ->
|
|
@@ -637,6 +732,7 @@ class EnrichedMarkdown
|
|
|
637
732
|
this@EnrichedMarkdown.onTaskListItemPressCallback?.invoke(taskIndex, checked, itemText)
|
|
638
733
|
}
|
|
639
734
|
onCopyRequest = ::forwardSegmentCopyRequest
|
|
735
|
+
onSelectionChangedCallback = ::onSegmentSelectionChanged
|
|
640
736
|
|
|
641
737
|
if (contextMenuItemTexts.isNotEmpty()) {
|
|
642
738
|
setContextMenuItems(contextMenuItemTexts, ::forwardContextMenuItemPress)
|
|
@@ -658,6 +754,7 @@ class EnrichedMarkdown
|
|
|
658
754
|
copyAsMarkdownLabel = this@EnrichedMarkdown.selectionMenuConfig.copyAsMarkdownLabel
|
|
659
755
|
contextMenuHidden = this@EnrichedMarkdown.contextMenuHidden
|
|
660
756
|
menuOptions = blockMenuOptions("table")
|
|
757
|
+
onMenuSuppressed = { markdown, text -> onBlockMenuSuppressed(this, "table", markdown, text) }
|
|
661
758
|
applyTableNode(segment.node)
|
|
662
759
|
}
|
|
663
760
|
|
|
@@ -669,6 +766,7 @@ class EnrichedMarkdown
|
|
|
669
766
|
copyAsMarkdownLabel = this@EnrichedMarkdown.selectionMenuConfig.copyAsMarkdownLabel
|
|
670
767
|
contextMenuHidden = this@EnrichedMarkdown.contextMenuHidden
|
|
671
768
|
menuOptions = blockMenuOptions("code")
|
|
769
|
+
onMenuSuppressed = { markdown, text -> onBlockMenuSuppressed(this, "code", markdown, text) }
|
|
672
770
|
onCopyPress = { code, language ->
|
|
673
771
|
this@EnrichedMarkdown.onCopyPressCallback?.invoke(code, language)
|
|
674
772
|
}
|
|
@@ -702,6 +800,12 @@ class EnrichedMarkdown
|
|
|
702
800
|
.getMethod("setMenuOptions", BlockMenuOptions::class.java)
|
|
703
801
|
.invoke(view, blockMenuOptions("math"))
|
|
704
802
|
setMathContextMenuHidden(view)
|
|
803
|
+
val onMenuSuppressed: (String, String) -> Unit = { markdown, text ->
|
|
804
|
+
onBlockMenuSuppressed(view, "math", markdown, text)
|
|
805
|
+
}
|
|
806
|
+
runCatching {
|
|
807
|
+
resolvedClass.getMethod("setOnMenuSuppressed", Function2::class.java).invoke(view, onMenuSuppressed)
|
|
808
|
+
}.onFailure { Log.e(TAG, "Failed to set onMenuSuppressed on math view", it) }
|
|
705
809
|
resolvedClass.getMethod("applyLatex", String::class.java).invoke(view, segment.latex)
|
|
706
810
|
view
|
|
707
811
|
} catch (e: Exception) {
|
|
@@ -789,6 +893,8 @@ class EnrichedMarkdown
|
|
|
789
893
|
}
|
|
790
894
|
|
|
791
895
|
emitLinkLayoutIfNeeded()
|
|
896
|
+
// Segments may have moved or been replaced; re-read the selection (deduplicated).
|
|
897
|
+
if (selectionOwner != null || activeBlock != null) selectionReporter.schedule() else selectionReporter.flushNow()
|
|
792
898
|
}
|
|
793
899
|
|
|
794
900
|
fun setEmitLinkLayout(enabled: Boolean) {
|
|
@@ -837,6 +943,7 @@ class EnrichedMarkdown
|
|
|
837
943
|
}
|
|
838
944
|
|
|
839
945
|
fun cleanup() {
|
|
946
|
+
selectionReporter.cancel()
|
|
840
947
|
executor.shutdownNow()
|
|
841
948
|
}
|
|
842
949
|
|
package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt
CHANGED
|
@@ -18,6 +18,7 @@ import com.swmansion.enriched.markdown.utils.text.view.SelectionMenuConfig
|
|
|
18
18
|
import com.swmansion.enriched.markdown.utils.text.view.applySelectableState
|
|
19
19
|
import com.swmansion.enriched.markdown.utils.text.view.cancelJSTouchForCheckboxTap
|
|
20
20
|
import com.swmansion.enriched.markdown.utils.text.view.cancelJSTouchForLinkTap
|
|
21
|
+
import com.swmansion.enriched.markdown.utils.text.view.clearTextSelection
|
|
21
22
|
import com.swmansion.enriched.markdown.utils.text.view.createSelectionActionModeCallback
|
|
22
23
|
import com.swmansion.enriched.markdown.utils.text.view.reallowParentInterceptIfLinkReleased
|
|
23
24
|
import com.swmansion.enriched.markdown.utils.text.view.setupAsMarkdownTextView
|
|
@@ -57,6 +58,10 @@ class EnrichedMarkdownInternalText
|
|
|
57
58
|
private var onContextMenuItemPress: ((itemText: String, selectedText: String, selectionStart: Int, selectionEnd: Int) -> Unit)? = null
|
|
58
59
|
var selectionMenuConfig: SelectionMenuConfig = SelectionMenuConfig()
|
|
59
60
|
var onCopyRequest: ((markdown: String, text: String, fullSelection: Boolean) -> Unit)? = null
|
|
61
|
+
|
|
62
|
+
// Read from onSelectionChanged, which TextView already calls from its own
|
|
63
|
+
// constructor — so it must stay nullable.
|
|
64
|
+
var onSelectionChangedCallback: ((view: EnrichedMarkdownInternalText, hasSelection: Boolean) -> Unit)? = null
|
|
60
65
|
private var activeActionMode: ActionMode? = null
|
|
61
66
|
var contextMenuHidden: Boolean = false
|
|
62
67
|
set(value) {
|
|
@@ -115,6 +120,20 @@ class EnrichedMarkdownInternalText
|
|
|
115
120
|
applySelectableState(selectable)
|
|
116
121
|
}
|
|
117
122
|
|
|
123
|
+
override fun onSelectionChanged(
|
|
124
|
+
selStart: Int,
|
|
125
|
+
selEnd: Int,
|
|
126
|
+
) {
|
|
127
|
+
super.onSelectionChanged(selStart, selEnd)
|
|
128
|
+
onSelectionChangedCallback?.invoke(this, selEnd > selStart)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Clears the selection and ends its ActionMode. */
|
|
132
|
+
fun clearSelection() {
|
|
133
|
+
clearTextSelection()
|
|
134
|
+
activeActionMode?.finish()
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
fun setContextMenuItems(
|
|
119
138
|
items: List<String>,
|
|
120
139
|
onPress: (itemText: String, selectedText: String, selectionStart: Int, selectionEnd: Int) -> Unit,
|
|
@@ -185,6 +185,20 @@ class EnrichedMarkdownManager :
|
|
|
185
185
|
view?.setEmitLinkLayout(emitLinkLayout)
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
@ReactProp(name = "emitSelectionChange", defaultBoolean = false)
|
|
189
|
+
override fun setEmitSelectionChange(
|
|
190
|
+
view: EnrichedMarkdown?,
|
|
191
|
+
emitSelectionChange: Boolean,
|
|
192
|
+
) {
|
|
193
|
+
view?.setEmitSelectionChange(emitSelectionChange)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Commands
|
|
197
|
+
|
|
198
|
+
override fun clearSelection(view: EnrichedMarkdown?) {
|
|
199
|
+
view?.clearSelection()
|
|
200
|
+
}
|
|
201
|
+
|
|
188
202
|
@ReactProp(name = "enableLinkPreview", defaultBoolean = true)
|
|
189
203
|
override fun setEnableLinkPreview(
|
|
190
204
|
view: EnrichedMarkdown?,
|
|
@@ -193,6 +207,14 @@ class EnrichedMarkdownManager :
|
|
|
193
207
|
// No-op on Android — only used on iOS
|
|
194
208
|
}
|
|
195
209
|
|
|
210
|
+
@ReactProp(name = "linkLongPressSelects", defaultBoolean = false)
|
|
211
|
+
override fun setLinkLongPressSelects(
|
|
212
|
+
view: EnrichedMarkdown?,
|
|
213
|
+
linkLongPressSelects: Boolean,
|
|
214
|
+
) {
|
|
215
|
+
// No-op on Android — only used on iOS
|
|
216
|
+
}
|
|
217
|
+
|
|
196
218
|
@ReactProp(name = "enableTaskListItemToggle", defaultBoolean = true)
|
|
197
219
|
override fun setEnableTaskListItemToggle(
|
|
198
220
|
view: EnrichedMarkdown?,
|