react-native-enriched-markdown-scaffold 1.0.2-scaffold.5 → 1.0.2-scaffold.7
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 +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +1 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +1 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +2 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +2 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +10 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +2 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +8 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +8 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/SelectionChangeEvent.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionChangeReporter.kt +2 -0
- package/docs/API_REFERENCE.md +14 -2
- package/docs/WEB.md +1 -0
- package/ios/EnrichedMarkdown.mm +39 -2
- package/ios/EnrichedMarkdownText.mm +37 -2
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +2 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +2 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +10 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +2 -0
- package/ios/utils/ENRMLinkChip.m +25 -6
- package/ios/utils/ENRMSelectionChange.h +24 -0
- package/ios/utils/ENRMSelectionChange.m +78 -0
- package/ios/utils/EditMenuUtils.h +3 -0
- package/ios/utils/EditMenuUtils.m +116 -0
- package/lib/module/EnrichedMarkdownNativeComponent.ts +11 -0
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +11 -0
- package/lib/module/jest/index.js +1 -0
- package/lib/module/jest/index.js.map +1 -1
- package/lib/module/native/EnrichedMarkdownText.js +2 -0
- package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +11 -0
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +11 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.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 +1 -1
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.d.ts +14 -2
- package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +8 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/EnrichedMarkdownNativeComponent.ts +11 -0
- package/src/EnrichedMarkdownTextNativeComponent.ts +11 -0
- package/src/jest/index.tsx +1 -0
- package/src/native/EnrichedMarkdownText.tsx +2 -0
- package/src/types/MarkdownTextProps.ts +14 -2
- package/src/types/events.ts +8 -0
package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java
CHANGED
|
@@ -44,6 +44,9 @@ public class EnrichedMarkdownManagerDelegate<T extends View, U extends BaseViewM
|
|
|
44
44
|
case "enableLinkPreview":
|
|
45
45
|
mViewManager.setEnableLinkPreview(view, value == null ? true : (boolean) value);
|
|
46
46
|
break;
|
|
47
|
+
case "linkLongPressSelects":
|
|
48
|
+
mViewManager.setLinkLongPressSelects(view, value == null ? false : (boolean) value);
|
|
49
|
+
break;
|
|
47
50
|
case "selectable":
|
|
48
51
|
mViewManager.setSelectable(view, value == null ? false : (boolean) value);
|
|
49
52
|
break;
|
package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java
CHANGED
|
@@ -22,6 +22,7 @@ public interface EnrichedMarkdownManagerInterface<T extends View> extends ViewMa
|
|
|
22
22
|
void setEmitSelectionChange(T view, boolean value);
|
|
23
23
|
void setEnableTaskListItemToggle(T view, boolean value);
|
|
24
24
|
void setEnableLinkPreview(T view, boolean value);
|
|
25
|
+
void setLinkLongPressSelects(T view, boolean value);
|
|
25
26
|
void setSelectable(T view, boolean value);
|
|
26
27
|
void setSelectionColor(T view, @Nullable Integer value);
|
|
27
28
|
void setSelectionHandleColor(T view, @Nullable Integer value);
|
|
@@ -44,6 +44,9 @@ public class EnrichedMarkdownTextManagerDelegate<T extends View, U extends BaseV
|
|
|
44
44
|
case "enableLinkPreview":
|
|
45
45
|
mViewManager.setEnableLinkPreview(view, value == null ? true : (boolean) value);
|
|
46
46
|
break;
|
|
47
|
+
case "linkLongPressSelects":
|
|
48
|
+
mViewManager.setLinkLongPressSelects(view, value == null ? false : (boolean) value);
|
|
49
|
+
break;
|
|
47
50
|
case "selectable":
|
|
48
51
|
mViewManager.setSelectable(view, value == null ? false : (boolean) value);
|
|
49
52
|
break;
|
|
@@ -22,6 +22,7 @@ public interface EnrichedMarkdownTextManagerInterface<T extends View> extends Vi
|
|
|
22
22
|
void setEmitSelectionChange(T view, boolean value);
|
|
23
23
|
void setEnableTaskListItemToggle(T view, boolean value);
|
|
24
24
|
void setEnableLinkPreview(T view, boolean value);
|
|
25
|
+
void setLinkLongPressSelects(T view, boolean value);
|
|
25
26
|
void setSelectable(T view, boolean value);
|
|
26
27
|
void setSelectionColor(T view, @Nullable Integer value);
|
|
27
28
|
void setSelectionHandleColor(T view, @Nullable Integer value);
|
package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp
CHANGED
|
@@ -87,6 +87,7 @@ payload.setProperty(runtime, "whole", event.whole);
|
|
|
87
87
|
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
88
88
|
payload.setProperty(runtime, "endRect", endRect);
|
|
89
89
|
}
|
|
90
|
+
payload.setProperty(runtime, "adjusting", event.adjusting);
|
|
90
91
|
return payload;
|
|
91
92
|
});
|
|
92
93
|
}
|
|
@@ -487,6 +488,7 @@ payload.setProperty(runtime, "whole", event.whole);
|
|
|
487
488
|
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
488
489
|
payload.setProperty(runtime, "endRect", endRect);
|
|
489
490
|
}
|
|
491
|
+
payload.setProperty(runtime, "adjusting", event.adjusting);
|
|
490
492
|
return payload;
|
|
491
493
|
});
|
|
492
494
|
}
|
package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h
CHANGED
|
@@ -69,6 +69,7 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
|
|
|
69
69
|
OnSelectionChangeRect rect;
|
|
70
70
|
OnSelectionChangeStartRect startRect;
|
|
71
71
|
OnSelectionChangeEndRect endRect;
|
|
72
|
+
bool adjusting;
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
struct OnTaskListItemPress {
|
|
@@ -395,6 +396,7 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
|
|
|
395
396
|
OnSelectionChangeRect rect;
|
|
396
397
|
OnSelectionChangeStartRect startRect;
|
|
397
398
|
OnSelectionChangeEndRect endRect;
|
|
399
|
+
bool adjusting;
|
|
398
400
|
};
|
|
399
401
|
|
|
400
402
|
struct OnTaskListItemPress {
|
|
@@ -25,6 +25,7 @@ EnrichedMarkdownProps::EnrichedMarkdownProps(
|
|
|
25
25
|
emitSelectionChange(convertRawProp(context, rawProps, "emitSelectionChange", sourceProps.emitSelectionChange, {false})),
|
|
26
26
|
enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
|
|
27
27
|
enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
|
|
28
|
+
linkLongPressSelects(convertRawProp(context, rawProps, "linkLongPressSelects", sourceProps.linkLongPressSelects, {false})),
|
|
28
29
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
29
30
|
selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
|
|
30
31
|
selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})),
|
|
@@ -84,6 +85,10 @@ folly::dynamic EnrichedMarkdownProps::getDiffProps(
|
|
|
84
85
|
result["enableLinkPreview"] = enableLinkPreview;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
if (linkLongPressSelects != oldProps->linkLongPressSelects) {
|
|
89
|
+
result["linkLongPressSelects"] = linkLongPressSelects;
|
|
90
|
+
}
|
|
91
|
+
|
|
87
92
|
if (selectable != oldProps->selectable) {
|
|
88
93
|
result["selectable"] = selectable;
|
|
89
94
|
}
|
|
@@ -318,6 +323,7 @@ EnrichedMarkdownTextProps::EnrichedMarkdownTextProps(
|
|
|
318
323
|
emitSelectionChange(convertRawProp(context, rawProps, "emitSelectionChange", sourceProps.emitSelectionChange, {false})),
|
|
319
324
|
enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
|
|
320
325
|
enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
|
|
326
|
+
linkLongPressSelects(convertRawProp(context, rawProps, "linkLongPressSelects", sourceProps.linkLongPressSelects, {false})),
|
|
321
327
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
322
328
|
selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
|
|
323
329
|
selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})),
|
|
@@ -377,6 +383,10 @@ folly::dynamic EnrichedMarkdownTextProps::getDiffProps(
|
|
|
377
383
|
result["enableLinkPreview"] = enableLinkPreview;
|
|
378
384
|
}
|
|
379
385
|
|
|
386
|
+
if (linkLongPressSelects != oldProps->linkLongPressSelects) {
|
|
387
|
+
result["linkLongPressSelects"] = linkLongPressSelects;
|
|
388
|
+
}
|
|
389
|
+
|
|
380
390
|
if (selectable != oldProps->selectable) {
|
|
381
391
|
result["selectable"] = selectable;
|
|
382
392
|
}
|
|
@@ -2890,6 +2890,7 @@ class EnrichedMarkdownProps final : public ViewProps {
|
|
|
2890
2890
|
bool emitSelectionChange{false};
|
|
2891
2891
|
bool enableTaskListItemToggle{true};
|
|
2892
2892
|
bool enableLinkPreview{true};
|
|
2893
|
+
bool linkLongPressSelects{false};
|
|
2893
2894
|
bool selectable{false};
|
|
2894
2895
|
SharedColor selectionColor{};
|
|
2895
2896
|
SharedColor selectionHandleColor{};
|
|
@@ -6935,6 +6936,7 @@ class EnrichedMarkdownTextProps final : public ViewProps {
|
|
|
6935
6936
|
bool emitSelectionChange{false};
|
|
6936
6937
|
bool enableTaskListItemToggle{true};
|
|
6937
6938
|
bool enableLinkPreview{true};
|
|
6939
|
+
bool linkLongPressSelects{false};
|
|
6938
6940
|
bool selectable{false};
|
|
6939
6941
|
SharedColor selectionColor{};
|
|
6940
6942
|
SharedColor selectionHandleColor{};
|
|
@@ -207,6 +207,14 @@ class EnrichedMarkdownManager :
|
|
|
207
207
|
// No-op on Android — only used on iOS
|
|
208
208
|
}
|
|
209
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
|
+
|
|
210
218
|
@ReactProp(name = "enableTaskListItemToggle", defaultBoolean = true)
|
|
211
219
|
override fun setEnableTaskListItemToggle(
|
|
212
220
|
view: EnrichedMarkdown?,
|
package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt
CHANGED
|
@@ -207,6 +207,14 @@ class EnrichedMarkdownTextManager :
|
|
|
207
207
|
// No-op on Android — only used on iOS
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
@ReactProp(name = "linkLongPressSelects", defaultBoolean = false)
|
|
211
|
+
override fun setLinkLongPressSelects(
|
|
212
|
+
view: EnrichedMarkdownText?,
|
|
213
|
+
linkLongPressSelects: Boolean,
|
|
214
|
+
) {
|
|
215
|
+
// No-op on Android — only used on iOS
|
|
216
|
+
}
|
|
217
|
+
|
|
210
218
|
@ReactProp(name = "enableTaskListItemToggle", defaultBoolean = true)
|
|
211
219
|
override fun setEnableTaskListItemToggle(
|
|
212
220
|
view: EnrichedMarkdownText?,
|
package/android/src/main/java/com/swmansion/enriched/markdown/events/SelectionChangeEvent.kt
CHANGED
|
@@ -26,6 +26,7 @@ class SelectionChangeEvent(
|
|
|
26
26
|
putMap("rect", snapshot.rect.toWritableMap())
|
|
27
27
|
putMap("startRect", snapshot.startRect.toWritableMap())
|
|
28
28
|
putMap("endRect", snapshot.endRect.toWritableMap())
|
|
29
|
+
putBoolean("adjusting", snapshot.adjusting)
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
private fun SelectionRect.toWritableMap(): WritableMap =
|
|
@@ -46,6 +46,8 @@ data class SelectionSnapshot(
|
|
|
46
46
|
val rect: SelectionRect,
|
|
47
47
|
val startRect: SelectionRect,
|
|
48
48
|
val endRect: SelectionRect,
|
|
49
|
+
// Not tracked on Android: the selection is reported continuously while a handle is dragged.
|
|
50
|
+
val adjusting: Boolean = false,
|
|
49
51
|
) {
|
|
50
52
|
companion object {
|
|
51
53
|
val INACTIVE =
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -248,13 +248,15 @@ interface SelectionChangeEvent {
|
|
|
248
248
|
/** Selected part of the first / last line — anchor a menu above the start or below the end. */
|
|
249
249
|
startRect: SelectionRect;
|
|
250
250
|
endRect: SelectionRect;
|
|
251
|
+
/** `true` while a selection handle is dragged (iOS; always `false` on Android). */
|
|
252
|
+
adjusting: boolean;
|
|
251
253
|
}
|
|
252
254
|
```
|
|
253
255
|
|
|
254
256
|
- Fires at most once per frame while the selection changes (payloads are deduplicated), and with `active: false` right away once it is gone — including when new `markdown` replaces the text.
|
|
255
257
|
- Rects are in dp, relative to the component's native view: add the origin from `ref.current.measureInWindow` to get window coordinates. Re-measure after scrolling instead of waiting for a new event.
|
|
256
258
|
- With `contextMenuHidden`, a long press on a table, math or code block (`flavor="github"`) fires the event with `source` set to the block kind, `whole: true` and every rect set to the block's frame. These blocks have no text selection, so without this they would offer no way to copy. Without `contextMenuHidden` the block menu shows as usual and no event fires.
|
|
257
|
-
-
|
|
259
|
+
- On iOS the selection isn't reported while a handle is dragged: the event fires with `adjusting: true` (and the selection as it was) when the drag begins, and with `adjusting: false` and the new selection when the finger lifts. Hide your menu while `adjusting` is `true`. Android has no such flag (`adjusting` is always `false`) but reports every step of the drag, so debounce before showing the menu there too.
|
|
258
260
|
- Within one component only one part holds a selection at a time: selecting in another text segment clears the previous one. To keep a single selection across several components, call `clearSelection()` on the previous one.
|
|
259
261
|
- Ignored on macOS and web.
|
|
260
262
|
|
|
@@ -268,7 +270,7 @@ const ref = useRef<EnrichedMarkdownTextInstance>(null);
|
|
|
268
270
|
markdown={content}
|
|
269
271
|
contextMenuHidden
|
|
270
272
|
onSelectionChange={(e) => {
|
|
271
|
-
if (!e.active) return hideMenu();
|
|
273
|
+
if (!e.active || e.adjusting) return hideMenu();
|
|
272
274
|
ref.current?.measureInWindow((x, y) =>
|
|
273
275
|
showMenuDebounced({ x: x + e.startRect.x, y: y + e.startRect.y }, e.markdown)
|
|
274
276
|
);
|
|
@@ -299,6 +301,16 @@ You can also control this behavior explicitly without providing a handler:
|
|
|
299
301
|
/>
|
|
300
302
|
```
|
|
301
303
|
|
|
304
|
+
### `linkLongPressSelects`
|
|
305
|
+
|
|
306
|
+
Long-pressing a link selects its label and shows the selection edit menu (the same one a manual selection gets), instead of the system link preview (iOS only). Takes precedence over `enableLinkPreview` and `onLinkLongPress`.
|
|
307
|
+
|
|
308
|
+
| Type | Default Value | Platform |
|
|
309
|
+
| --------- | ------------- | -------- |
|
|
310
|
+
| `boolean` | `false` | iOS |
|
|
311
|
+
|
|
312
|
+
Only the link label is selected, not the chip padding; the selection handles can be dragged to extend it. Long-pressing inline math always behaves this way, without the prop.
|
|
313
|
+
|
|
302
314
|
### `selectable`
|
|
303
315
|
|
|
304
316
|
Whether text can be selected.
|
package/docs/WEB.md
CHANGED
|
@@ -37,6 +37,7 @@ The web implementation also exports `WebMarkdownTextProps` which extends `Enrich
|
|
|
37
37
|
|---|---|
|
|
38
38
|
| `flavor` | The web renderer always uses full GFM capabilities. On native, `flavor` controls whether a single `TextView` (CommonMark) or container-based renderer (GitHub) is used; the DOM has no such constraint. |
|
|
39
39
|
| `enableLinkPreview` | iOS-only feature (native link preview on long press). |
|
|
40
|
+
| `linkLongPressSelects` | iOS-only feature (selects a link on long press instead of the link preview). |
|
|
40
41
|
| `allowFontScaling` / `maxFontSizeMultiplier` | React Native text scaling props. Browsers handle font scaling natively via OS accessibility settings. |
|
|
41
42
|
| `streamingAnimation` | Native-only tail fade-in animation. Not yet implemented on web. |
|
|
42
43
|
| `streamingConfig` | Native-only streaming table configuration. Not yet implemented on web. |
|
package/ios/EnrichedMarkdown.mm
CHANGED
|
@@ -107,6 +107,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
107
107
|
BOOL _allowTrailingMargin;
|
|
108
108
|
BOOL _selectable;
|
|
109
109
|
BOOL _enableLinkPreview;
|
|
110
|
+
BOOL _linkLongPressSelects;
|
|
110
111
|
BOOL _enableTaskListItemToggle;
|
|
111
112
|
BOOL _contextMenuHidden;
|
|
112
113
|
BOOL _streamingAnimation;
|
|
@@ -130,6 +131,9 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
130
131
|
NSArray<NSDictionary *> *_lastLinkLayout;
|
|
131
132
|
|
|
132
133
|
ENRMSelectionChangeReporter *_selectionReporter;
|
|
134
|
+
#if !TARGET_OS_OSX
|
|
135
|
+
ENRMSelectionGestureTracker *_selectionGestures;
|
|
136
|
+
#endif
|
|
133
137
|
// At most one segment holds a selection; a new one clears the previous.
|
|
134
138
|
__weak ENRMPlatformTextView *_selectionOwner;
|
|
135
139
|
// A block long-pressed while contextMenuHidden is on, reported as the selection.
|
|
@@ -224,6 +228,20 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
224
228
|
emitter->onSelectionChange(
|
|
225
229
|
ENRMSelectionChangeEventFromPayload<EnrichedMarkdownEventEmitter::OnSelectionChange>(payload));
|
|
226
230
|
}];
|
|
231
|
+
#if !TARGET_OS_OSX
|
|
232
|
+
// A handle drag starting or ending is reported right away, even when the
|
|
233
|
+
// selection itself is unchanged.
|
|
234
|
+
_selectionGestures = [[ENRMSelectionGestureTracker alloc] initWithChange:^{
|
|
235
|
+
EnrichedMarkdown *strongSelf = weakSelf;
|
|
236
|
+
if (!strongSelf)
|
|
237
|
+
return;
|
|
238
|
+
UITextView *owner = strongSelf->_selectionOwner;
|
|
239
|
+
if (owner)
|
|
240
|
+
[strongSelf->_selectionGestures trackTextView:owner];
|
|
241
|
+
[strongSelf->_selectionReporter forgetLastReported];
|
|
242
|
+
[strongSelf->_selectionReporter flushNow];
|
|
243
|
+
}];
|
|
244
|
+
#endif
|
|
227
245
|
}
|
|
228
246
|
return self;
|
|
229
247
|
}
|
|
@@ -261,6 +279,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
261
279
|
payload[ENRMSelectionSourceKey] = @"selection";
|
|
262
280
|
payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
|
|
263
281
|
payload[ENRMSelectionWholeKey] = @(whole);
|
|
282
|
+
payload[ENRMSelectionAdjustingKey] = @(_selectionGestures.adjusting);
|
|
264
283
|
return payload;
|
|
265
284
|
#else
|
|
266
285
|
return ENRMInactiveSelectionPayload();
|
|
@@ -914,6 +933,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
914
933
|
|
|
915
934
|
#if !TARGET_OS_OSX
|
|
916
935
|
view.textView.delegate = self;
|
|
936
|
+
[_selectionGestures trackTextView:view.textView];
|
|
917
937
|
#else
|
|
918
938
|
__weak EnrichedMarkdown *weakSelf = self;
|
|
919
939
|
[view setContextMenuProvider:^NSMenu *_Nullable(NSMenu *baseMenu, NSTextView *textView) {
|
|
@@ -1153,6 +1173,7 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
1153
1173
|
}
|
|
1154
1174
|
|
|
1155
1175
|
_enableLinkPreview = newViewProps.enableLinkPreview;
|
|
1176
|
+
_linkLongPressSelects = newViewProps.linkLongPressSelects;
|
|
1156
1177
|
_enableTaskListItemToggle = newViewProps.enableTaskListItemToggle;
|
|
1157
1178
|
_contextMenuHidden = newViewProps.contextMenuHidden;
|
|
1158
1179
|
|
|
@@ -1310,6 +1331,9 @@ static char kENRMSegmentFadeAnimatorKey;
|
|
|
1310
1331
|
_emitLinkLayout = NO;
|
|
1311
1332
|
_lastLinkLayout = nil;
|
|
1312
1333
|
_selectionReporter.enabled = NO;
|
|
1334
|
+
#if !TARGET_OS_OSX
|
|
1335
|
+
[_selectionGestures reset];
|
|
1336
|
+
#endif
|
|
1313
1337
|
_selectionOwner = nil;
|
|
1314
1338
|
[self clearActiveBlock];
|
|
1315
1339
|
_md4cFlags = [EnrichedMarkdown flagsFromProps:resetProps->md4cFlags];
|
|
@@ -1536,6 +1560,8 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1536
1560
|
#if !TARGET_OS_OSX
|
|
1537
1561
|
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
1538
1562
|
{
|
|
1563
|
+
[_selectionGestures trackTextView:textView];
|
|
1564
|
+
ENRMDismissSelectionEditMenuIfMoved(textView);
|
|
1539
1565
|
if (textView.selectedRange.length > 0) {
|
|
1540
1566
|
// Take ownership first so the previous owner's own "cleared" callback is ignored.
|
|
1541
1567
|
ENRMPlatformTextView *previous = _selectionOwner;
|
|
@@ -1613,8 +1639,7 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1613
1639
|
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
1614
1640
|
return;
|
|
1615
1641
|
}
|
|
1616
|
-
|
|
1617
|
-
strongTextView.selectedRange = characterRange;
|
|
1642
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
1618
1643
|
});
|
|
1619
1644
|
}
|
|
1620
1645
|
return NO;
|
|
@@ -1631,6 +1656,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownCls(void)
|
|
|
1631
1656
|
|
|
1632
1657
|
NSString *urlString = linkURLAtRange(textView, characterRange);
|
|
1633
1658
|
|
|
1659
|
+
if (urlString && _linkLongPressSelects) {
|
|
1660
|
+
__weak UITextView *weakTextView = textView;
|
|
1661
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
1662
|
+
UITextView *strongTextView = weakTextView;
|
|
1663
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
1667
|
+
});
|
|
1668
|
+
return NO;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1634
1671
|
if (!urlString || _enableLinkPreview) {
|
|
1635
1672
|
return YES;
|
|
1636
1673
|
}
|
|
@@ -87,6 +87,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
87
87
|
CGFloat _lastElementMarginBottom;
|
|
88
88
|
BOOL _allowTrailingMargin;
|
|
89
89
|
BOOL _enableLinkPreview;
|
|
90
|
+
BOOL _linkLongPressSelects;
|
|
90
91
|
BOOL _enableTaskListItemToggle;
|
|
91
92
|
BOOL _contextMenuHidden;
|
|
92
93
|
BOOL _streamingAnimation;
|
|
@@ -118,6 +119,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
118
119
|
NSArray<NSDictionary *> *_lastLinkLayout;
|
|
119
120
|
|
|
120
121
|
ENRMSelectionChangeReporter *_selectionReporter;
|
|
122
|
+
#if !TARGET_OS_OSX
|
|
123
|
+
ENRMSelectionGestureTracker *_selectionGestures;
|
|
124
|
+
#endif
|
|
121
125
|
|
|
122
126
|
NSLineBreakStrategy _lineBreakStrategy;
|
|
123
127
|
|
|
@@ -299,6 +303,19 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
299
303
|
emitter->onSelectionChange(
|
|
300
304
|
ENRMSelectionChangeEventFromPayload<EnrichedMarkdownTextEventEmitter::OnSelectionChange>(payload));
|
|
301
305
|
}];
|
|
306
|
+
#if !TARGET_OS_OSX
|
|
307
|
+
// A handle drag starting or ending is reported right away, even when the
|
|
308
|
+
// selection itself is unchanged.
|
|
309
|
+
_selectionGestures = [[ENRMSelectionGestureTracker alloc] initWithChange:^{
|
|
310
|
+
EnrichedMarkdownText *strongSelf = weakSelf;
|
|
311
|
+
if (!strongSelf)
|
|
312
|
+
return;
|
|
313
|
+
[strongSelf->_selectionGestures trackTextView:strongSelf->_textView];
|
|
314
|
+
[strongSelf->_selectionReporter forgetLastReported];
|
|
315
|
+
[strongSelf->_selectionReporter flushNow];
|
|
316
|
+
}];
|
|
317
|
+
[_selectionGestures trackTextView:_textView];
|
|
318
|
+
#endif
|
|
302
319
|
}
|
|
303
320
|
|
|
304
321
|
/// The current selection as an `onSelectionChange` payload. Markdown and
|
|
@@ -318,6 +335,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
318
335
|
payload[ENRMSelectionSourceKey] = @"selection";
|
|
319
336
|
payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
|
|
320
337
|
payload[ENRMSelectionWholeKey] = @([selection[ENRMSelectionFullKey] boolValue] && _cachedMarkdown.length > 0);
|
|
338
|
+
payload[ENRMSelectionAdjustingKey] = @(_selectionGestures.adjusting);
|
|
321
339
|
return payload;
|
|
322
340
|
#else
|
|
323
341
|
return ENRMInactiveSelectionPayload();
|
|
@@ -653,6 +671,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
653
671
|
}
|
|
654
672
|
|
|
655
673
|
_enableLinkPreview = newViewProps.enableLinkPreview;
|
|
674
|
+
_linkLongPressSelects = newViewProps.linkLongPressSelects;
|
|
656
675
|
_enableTaskListItemToggle = newViewProps.enableTaskListItemToggle;
|
|
657
676
|
_contextMenuHidden = newViewProps.contextMenuHidden;
|
|
658
677
|
|
|
@@ -784,6 +803,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
|
|
|
784
803
|
_emitLinkLayout = NO;
|
|
785
804
|
_lastLinkLayout = nil;
|
|
786
805
|
_selectionReporter.enabled = NO;
|
|
806
|
+
#if !TARGET_OS_OSX
|
|
807
|
+
[_selectionGestures reset];
|
|
808
|
+
#endif
|
|
787
809
|
if (_textView != nil) {
|
|
788
810
|
ENRMSetAttributedText(_textView, [[NSAttributedString alloc] initWithString:@""]);
|
|
789
811
|
_textView.hidden = YES;
|
|
@@ -925,8 +947,7 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
925
947
|
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
926
948
|
return;
|
|
927
949
|
}
|
|
928
|
-
|
|
929
|
-
strongTextView.selectedRange = characterRange;
|
|
950
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
930
951
|
});
|
|
931
952
|
}
|
|
932
953
|
return NO;
|
|
@@ -943,6 +964,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
943
964
|
|
|
944
965
|
NSString *urlString = linkURLAtRange(textView, characterRange);
|
|
945
966
|
|
|
967
|
+
if (urlString && _linkLongPressSelects) {
|
|
968
|
+
__weak UITextView *weakTextView = textView;
|
|
969
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
970
|
+
UITextView *strongTextView = weakTextView;
|
|
971
|
+
if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
|
|
975
|
+
});
|
|
976
|
+
return NO;
|
|
977
|
+
}
|
|
978
|
+
|
|
946
979
|
if (!urlString || _enableLinkPreview) {
|
|
947
980
|
return YES;
|
|
948
981
|
}
|
|
@@ -955,6 +988,8 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
|
|
|
955
988
|
|
|
956
989
|
- (void)textViewDidChangeSelection:(UITextView *)textView
|
|
957
990
|
{
|
|
991
|
+
[_selectionGestures trackTextView:textView];
|
|
992
|
+
ENRMDismissSelectionEditMenuIfMoved(textView);
|
|
958
993
|
[_selectionReporter selectionChanged:textView.selectedRange.length > 0];
|
|
959
994
|
}
|
|
960
995
|
|
|
@@ -87,6 +87,7 @@ payload.setProperty(runtime, "whole", event.whole);
|
|
|
87
87
|
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
88
88
|
payload.setProperty(runtime, "endRect", endRect);
|
|
89
89
|
}
|
|
90
|
+
payload.setProperty(runtime, "adjusting", event.adjusting);
|
|
90
91
|
return payload;
|
|
91
92
|
});
|
|
92
93
|
}
|
|
@@ -487,6 +488,7 @@ payload.setProperty(runtime, "whole", event.whole);
|
|
|
487
488
|
endRect.setProperty(runtime, "height", event.endRect.height);
|
|
488
489
|
payload.setProperty(runtime, "endRect", endRect);
|
|
489
490
|
}
|
|
491
|
+
payload.setProperty(runtime, "adjusting", event.adjusting);
|
|
490
492
|
return payload;
|
|
491
493
|
});
|
|
492
494
|
}
|
|
@@ -69,6 +69,7 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
|
|
|
69
69
|
OnSelectionChangeRect rect;
|
|
70
70
|
OnSelectionChangeStartRect startRect;
|
|
71
71
|
OnSelectionChangeEndRect endRect;
|
|
72
|
+
bool adjusting;
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
struct OnTaskListItemPress {
|
|
@@ -395,6 +396,7 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
|
|
|
395
396
|
OnSelectionChangeRect rect;
|
|
396
397
|
OnSelectionChangeStartRect startRect;
|
|
397
398
|
OnSelectionChangeEndRect endRect;
|
|
399
|
+
bool adjusting;
|
|
398
400
|
};
|
|
399
401
|
|
|
400
402
|
struct OnTaskListItemPress {
|
|
@@ -25,6 +25,7 @@ EnrichedMarkdownProps::EnrichedMarkdownProps(
|
|
|
25
25
|
emitSelectionChange(convertRawProp(context, rawProps, "emitSelectionChange", sourceProps.emitSelectionChange, {false})),
|
|
26
26
|
enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
|
|
27
27
|
enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
|
|
28
|
+
linkLongPressSelects(convertRawProp(context, rawProps, "linkLongPressSelects", sourceProps.linkLongPressSelects, {false})),
|
|
28
29
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
29
30
|
selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
|
|
30
31
|
selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})),
|
|
@@ -84,6 +85,10 @@ folly::dynamic EnrichedMarkdownProps::getDiffProps(
|
|
|
84
85
|
result["enableLinkPreview"] = enableLinkPreview;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
if (linkLongPressSelects != oldProps->linkLongPressSelects) {
|
|
89
|
+
result["linkLongPressSelects"] = linkLongPressSelects;
|
|
90
|
+
}
|
|
91
|
+
|
|
87
92
|
if (selectable != oldProps->selectable) {
|
|
88
93
|
result["selectable"] = selectable;
|
|
89
94
|
}
|
|
@@ -318,6 +323,7 @@ EnrichedMarkdownTextProps::EnrichedMarkdownTextProps(
|
|
|
318
323
|
emitSelectionChange(convertRawProp(context, rawProps, "emitSelectionChange", sourceProps.emitSelectionChange, {false})),
|
|
319
324
|
enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
|
|
320
325
|
enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
|
|
326
|
+
linkLongPressSelects(convertRawProp(context, rawProps, "linkLongPressSelects", sourceProps.linkLongPressSelects, {false})),
|
|
321
327
|
selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
|
|
322
328
|
selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
|
|
323
329
|
selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})),
|
|
@@ -377,6 +383,10 @@ folly::dynamic EnrichedMarkdownTextProps::getDiffProps(
|
|
|
377
383
|
result["enableLinkPreview"] = enableLinkPreview;
|
|
378
384
|
}
|
|
379
385
|
|
|
386
|
+
if (linkLongPressSelects != oldProps->linkLongPressSelects) {
|
|
387
|
+
result["linkLongPressSelects"] = linkLongPressSelects;
|
|
388
|
+
}
|
|
389
|
+
|
|
380
390
|
if (selectable != oldProps->selectable) {
|
|
381
391
|
result["selectable"] = selectable;
|
|
382
392
|
}
|
|
@@ -2890,6 +2890,7 @@ class EnrichedMarkdownProps final : public ViewProps {
|
|
|
2890
2890
|
bool emitSelectionChange{false};
|
|
2891
2891
|
bool enableTaskListItemToggle{true};
|
|
2892
2892
|
bool enableLinkPreview{true};
|
|
2893
|
+
bool linkLongPressSelects{false};
|
|
2893
2894
|
bool selectable{false};
|
|
2894
2895
|
SharedColor selectionColor{};
|
|
2895
2896
|
SharedColor selectionHandleColor{};
|
|
@@ -6935,6 +6936,7 @@ class EnrichedMarkdownTextProps final : public ViewProps {
|
|
|
6935
6936
|
bool emitSelectionChange{false};
|
|
6936
6937
|
bool enableTaskListItemToggle{true};
|
|
6937
6938
|
bool enableLinkPreview{true};
|
|
6939
|
+
bool linkLongPressSelects{false};
|
|
6938
6940
|
bool selectable{false};
|
|
6939
6941
|
SharedColor selectionColor{};
|
|
6940
6942
|
SharedColor selectionHandleColor{};
|
package/ios/utils/ENRMLinkChip.m
CHANGED
|
@@ -134,11 +134,32 @@ void ENRMEnumerateLinkChipFragments(NSLayoutManager *layoutManager, NSTextContai
|
|
|
134
134
|
|
|
135
135
|
CGRect textRect = [layoutManager boundingRectForGlyphRange:intersect
|
|
136
136
|
inTextContainer:textContainer];
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
NSRange fragmentChars = [layoutManager characterRangeForGlyphRange:intersect
|
|
138
|
+
actualGlyphRange:NULL];
|
|
139
|
+
NSUInteger lineEnd = NSMaxRange(lineRange);
|
|
140
|
+
CGFloat left =
|
|
141
|
+
lineRect.origin.x + [layoutManager locationForGlyphAtIndex:intersect.location].x;
|
|
142
|
+
|
|
143
|
+
NSUInteger visibleCharEnd = NSMaxRange(fragmentChars);
|
|
144
|
+
NSString *chars = storage.string;
|
|
145
|
+
NSCharacterSet *breakable = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
|
146
|
+
while (visibleCharEnd > fragmentChars.location &&
|
|
147
|
+
[chars characterAtIndex:visibleCharEnd - 1] != kSpacerChar &&
|
|
148
|
+
[breakable characterIsMember:[chars characterAtIndex:visibleCharEnd - 1]]) {
|
|
149
|
+
visibleCharEnd--;
|
|
150
|
+
}
|
|
151
|
+
NSUInteger visibleGlyphEnd = NSMaxRange(intersect);
|
|
152
|
+
if (visibleCharEnd < NSMaxRange(fragmentChars)) {
|
|
153
|
+
visibleGlyphEnd = [layoutManager glyphIndexForCharacterAtIndex:visibleCharEnd];
|
|
154
|
+
}
|
|
139
155
|
|
|
140
|
-
|
|
141
|
-
|
|
156
|
+
CGFloat right;
|
|
157
|
+
if (visibleGlyphEnd < lineEnd) {
|
|
158
|
+
right =
|
|
159
|
+
lineRect.origin.x + [layoutManager locationForGlyphAtIndex:visibleGlyphEnd].x;
|
|
160
|
+
} else {
|
|
161
|
+
right = CGRectGetMaxX(usedRect);
|
|
162
|
+
}
|
|
142
163
|
if (isLast && paddingHorizontal > 0) {
|
|
143
164
|
NSUInteger lastGlyph = NSMaxRange(intersect) - 1;
|
|
144
165
|
CGFloat spacerX =
|
|
@@ -146,8 +167,6 @@ void ENRMEnumerateLinkChipFragments(NSLayoutManager *layoutManager, NSTextContai
|
|
|
146
167
|
right = MAX(right, spacerX + paddingHorizontal);
|
|
147
168
|
}
|
|
148
169
|
|
|
149
|
-
NSRange fragmentChars = [layoutManager characterRangeForGlyphRange:intersect
|
|
150
|
-
actualGlyphRange:NULL];
|
|
151
170
|
UIFont *font = chipFontInRange(storage, fragmentChars);
|
|
152
171
|
CGFloat top = CGRectGetMinY(textRect);
|
|
153
172
|
CGFloat bottom = CGRectGetMaxY(textRect);
|
|
@@ -14,6 +14,7 @@ extern NSString *const ENRMSelectionWholeKey;
|
|
|
14
14
|
extern NSString *const ENRMSelectionRectKey;
|
|
15
15
|
extern NSString *const ENRMSelectionStartRectKey;
|
|
16
16
|
extern NSString *const ENRMSelectionEndRectKey;
|
|
17
|
+
extern NSString *const ENRMSelectionAdjustingKey;
|
|
17
18
|
/// Only in `ENRMTextSelectionInTextView` results: whether the range spans the
|
|
18
19
|
/// whole text (same threshold `markdownForRange` uses for the cached markdown).
|
|
19
20
|
extern NSString *const ENRMSelectionFullKey;
|
|
@@ -63,6 +64,28 @@ NSDictionary *_Nullable ENRMTextSelectionInTextView(UITextView *textView, UIView
|
|
|
63
64
|
|
|
64
65
|
@end
|
|
65
66
|
|
|
67
|
+
#if !TARGET_OS_OSX
|
|
68
|
+
/// Tells when the user is dragging a selection handle (or holding the loupe).
|
|
69
|
+
/// `UITextView` doesn't call `textViewDidChangeSelection:` during the drag, so
|
|
70
|
+
/// this watches the text view's own selection gestures: every recognizer of
|
|
71
|
+
/// the view and its subviews except scroll, pinch and taps. UIKit adds the
|
|
72
|
+
/// handle recognizers lazily, so call `trackTextView:` again on each selection
|
|
73
|
+
/// change. `change` runs whenever `adjusting` flips.
|
|
74
|
+
@interface ENRMSelectionGestureTracker : NSObject
|
|
75
|
+
|
|
76
|
+
- (instancetype)initWithChange:(void (^)(void))change NS_DESIGNATED_INITIALIZER;
|
|
77
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
78
|
+
|
|
79
|
+
/// A tracked gesture is in `Began` / `Changed`.
|
|
80
|
+
@property (nonatomic, readonly) BOOL adjusting;
|
|
81
|
+
|
|
82
|
+
- (void)trackTextView:(UITextView *)textView;
|
|
83
|
+
/// Clears `adjusting` without calling `change` (view recycling).
|
|
84
|
+
- (void)reset;
|
|
85
|
+
|
|
86
|
+
@end
|
|
87
|
+
#endif
|
|
88
|
+
|
|
66
89
|
#ifdef __cplusplus
|
|
67
90
|
/// Converts a payload into a codegen `OnSelectionChange` struct. Templated
|
|
68
91
|
/// because each component has its own (structurally identical) event struct.
|
|
@@ -74,6 +97,7 @@ template <typename Event> inline Event ENRMSelectionChangeEventFromPayload(NSDic
|
|
|
74
97
|
event.text = std::string([payload[ENRMSelectionTextKey] UTF8String] ?: "");
|
|
75
98
|
event.markdown = std::string([payload[ENRMSelectionMarkdownKey] UTF8String] ?: "");
|
|
76
99
|
event.whole = [payload[ENRMSelectionWholeKey] boolValue];
|
|
100
|
+
event.adjusting = [payload[ENRMSelectionAdjustingKey] boolValue];
|
|
77
101
|
|
|
78
102
|
auto assign = [](auto &target, NSValue *value) {
|
|
79
103
|
#if TARGET_OS_OSX
|