react-native-jet-markdown 0.2.1 → 0.2.3-beta.0
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/JetMarkdown.podspec +1 -1
- package/README.md +31 -82
- package/android/src/main/cpp/JniBindings.cpp +0 -106
- package/android/src/main/java/com/jetmarkdown/JetMarkdownNative.kt +0 -79
- package/android/src/main/java/com/jetmarkdown/JetMarkdownPackage.kt +1 -2
- package/android/src/main/java/com/jetmarkdown/JetMarkdownView.kt +11 -11
- package/android/src/main/java/com/jetmarkdown/render/spans/MarkdownLineHeightSpan.kt +2 -13
- package/android/src/main/java/com/jetmarkdown/views/BlockStackView.kt +49 -22
- package/android/src/main/java/com/jetmarkdown/views/BlockTextView.kt +2 -0
- package/android/src/main/java/com/jetmarkdown/views/TableBlockView.kt +11 -3
- package/cpp/react/override/react/renderer/components/JetMarkdownViewSpec/ComponentDescriptors.h +0 -4
- package/ios/JetMarkdownView.mm +9 -16
- package/ios/measure/JMDMarkdownMeasurer.mm +1 -1
- package/ios/render/JMDBlock.h +7 -0
- package/ios/render/JMDBlock.m +2 -0
- package/ios/render/JMDBlockRenderer.mm +27 -1
- package/ios/render/JMDRenderedContent.mm +36 -11
- package/ios/views/JMDBlockStackView.m +36 -14
- package/ios/views/JMDBlockTextView.h +6 -1
- package/ios/views/JMDBlockTextView.m +90 -127
- package/ios/views/JMDBoxViews.m +14 -11
- package/ios/views/JMDTableView.m +15 -8
- package/lib/module/index.js +0 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +0 -127
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +3 -5
- package/src/index.tsx +0 -9
- package/src/types.ts +0 -134
- package/android/src/main/java/com/jetmarkdown/editor/EditorSpans.kt +0 -217
- package/android/src/main/java/com/jetmarkdown/editor/JetMarkdownEditorManager.kt +0 -224
- package/android/src/main/java/com/jetmarkdown/editor/JetMarkdownEditorView.kt +0 -1736
- package/cpp/core/AstToMarkdown.cpp +0 -549
- package/cpp/core/AstToMarkdown.h +0 -16
- package/cpp/core/EditorRuns.cpp +0 -640
- package/cpp/core/EditorRuns.h +0 -94
- package/cpp/core/EditorText.cpp +0 -15
- package/cpp/core/EditorText.h +0 -18
- package/cpp/react/JetMarkdownEditorShadowNode.cpp +0 -54
- package/cpp/react/JetMarkdownEditorShadowNode.h +0 -55
- package/cpp/react/JetMarkdownEditorState.h +0 -35
- package/cpp/tests/parser_tests.cpp +0 -662
- package/cpp/tests/run_tests.sh +0 -25
- package/ios/editor/JetMarkdownEditor.h +0 -12
- package/ios/editor/JetMarkdownEditor.mm +0 -2002
- package/lib/module/JetMarkdownEditor.js +0 -85
- package/lib/module/JetMarkdownEditor.js.map +0 -1
- package/lib/module/JetMarkdownEditor.native.js +0 -244
- package/lib/module/JetMarkdownEditor.native.js.map +0 -1
- package/lib/module/JetMarkdownEditorNativeComponent.ts +0 -173
- package/lib/module/useJetMarkdownEditor.js +0 -41
- package/lib/module/useJetMarkdownEditor.js.map +0 -1
- package/lib/typescript/src/JetMarkdownEditor.d.ts +0 -6
- package/lib/typescript/src/JetMarkdownEditor.d.ts.map +0 -1
- package/lib/typescript/src/JetMarkdownEditor.native.d.ts +0 -6
- package/lib/typescript/src/JetMarkdownEditor.native.d.ts.map +0 -1
- package/lib/typescript/src/JetMarkdownEditorNativeComponent.d.ts +0 -105
- package/lib/typescript/src/JetMarkdownEditorNativeComponent.d.ts.map +0 -1
- package/lib/typescript/src/useJetMarkdownEditor.d.ts +0 -36
- package/lib/typescript/src/useJetMarkdownEditor.d.ts.map +0 -1
- package/src/JetMarkdownEditor.native.tsx +0 -301
- package/src/JetMarkdownEditor.tsx +0 -90
- package/src/JetMarkdownEditorNativeComponent.ts +0 -173
- package/src/useJetMarkdownEditor.ts +0 -50
package/cpp/react/override/react/renderer/components/JetMarkdownViewSpec/ComponentDescriptors.h
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
9
9
|
|
|
10
|
-
#include "../../../../../JetMarkdownEditorShadowNode.h"
|
|
11
10
|
#include "../../../../../JetMarkdownShadowNode.h"
|
|
12
11
|
|
|
13
12
|
namespace facebook::react {
|
|
@@ -15,7 +14,4 @@ namespace facebook::react {
|
|
|
15
14
|
using JetMarkdownViewComponentDescriptor =
|
|
16
15
|
ConcreteComponentDescriptor<JetMarkdownShadowNode>;
|
|
17
16
|
|
|
18
|
-
using JetMarkdownEditorComponentDescriptor =
|
|
19
|
-
ConcreteComponentDescriptor<JetMarkdownEditorShadowNode>;
|
|
20
|
-
|
|
21
17
|
} // namespace facebook::react
|
package/ios/JetMarkdownView.mm
CHANGED
|
@@ -41,8 +41,9 @@ static BOOL JMDIsScrollInProgress(UIView *view);
|
|
|
41
41
|
NSString *_stylesJson;
|
|
42
42
|
BOOL _allowFontScaling;
|
|
43
43
|
JMDBlockStackView *_stack;
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
// Layout objects are cached per (content, width, image sizes, font
|
|
45
|
+
// scale), so identity says whether the bound view tree is still current.
|
|
46
|
+
JMDWidthLayout *_boundLayout;
|
|
46
47
|
// url -> @[w, h] points: from the images prop (wins) and loaded bitmaps.
|
|
47
48
|
NSMutableDictionary<NSString *, NSArray<NSNumber *> *> *_propImageSizes;
|
|
48
49
|
NSMutableDictionary<NSString *, NSArray<NSNumber *> *> *_loadedImageSizes;
|
|
@@ -346,7 +347,7 @@ static void JMDSetNeedsDisplayDeep(UIView *view) {
|
|
|
346
347
|
// Dynamic (platform) colors resolve at draw time for text, but border
|
|
347
348
|
// and background colors snapshot into CGColors when blocks bind; rebind
|
|
348
349
|
// so they re-resolve under the new appearance.
|
|
349
|
-
|
|
350
|
+
_boundLayout = nil;
|
|
350
351
|
[self setNeedsLayout];
|
|
351
352
|
JMDSetNeedsDisplayDeep(self);
|
|
352
353
|
}
|
|
@@ -449,7 +450,7 @@ static void JMDSetNeedsDisplayDeep(UIView *view) {
|
|
|
449
450
|
[super prepareForRecycle];
|
|
450
451
|
_markdown = @"";
|
|
451
452
|
_stylesJson = @"";
|
|
452
|
-
|
|
453
|
+
_boundLayout = nil;
|
|
453
454
|
_state = nullptr;
|
|
454
455
|
[_propImageSizes removeAllObjects];
|
|
455
456
|
[_loadedImageSizes removeAllObjects];
|
|
@@ -463,9 +464,9 @@ static void JMDSetNeedsDisplayDeep(UIView *view) {
|
|
|
463
464
|
|
|
464
465
|
const CGFloat contentWidth =
|
|
465
466
|
self.bounds.size.width - styles.paddingLeft - styles.paddingRight;
|
|
466
|
-
if (contentWidth <= 0
|
|
467
|
+
if (contentWidth <= 0) {
|
|
467
468
|
[_stack setBlocks:@[] gap:0];
|
|
468
|
-
|
|
469
|
+
_boundLayout = nil;
|
|
469
470
|
return;
|
|
470
471
|
}
|
|
471
472
|
|
|
@@ -477,16 +478,8 @@ static void JMDSetNeedsDisplayDeep(UIView *view) {
|
|
|
477
478
|
NSDictionary *imageSizes = [self mergedImageSizes];
|
|
478
479
|
JMDWidthLayout *layout = [content layoutForWidth:contentWidth imageSizes:imageSizes];
|
|
479
480
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
NSString *key = [NSString stringWithFormat:@"%@\x1f%@\x1f%@\x1f%.3f",
|
|
483
|
-
_markdown,
|
|
484
|
-
_stylesJson,
|
|
485
|
-
[JMDRenderedContent keyForImageSizes:imageSizes],
|
|
486
|
-
fontScale];
|
|
487
|
-
if (![key isEqualToString:_boundKey] || _boundWidth != contentWidth) {
|
|
488
|
-
_boundKey = key;
|
|
489
|
-
_boundWidth = contentWidth;
|
|
481
|
+
if (layout != _boundLayout) {
|
|
482
|
+
_boundLayout = layout;
|
|
490
483
|
[_stack setBlocks:layout.measured gap:content.gap];
|
|
491
484
|
}
|
|
492
485
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
fontScale:(CGFloat)fontScale {
|
|
13
13
|
JMDStyleConfig *styles = [JMDStyleConfig configWithJson:stylesJson];
|
|
14
14
|
const CGFloat contentWidth = maxWidth - styles.paddingLeft - styles.paddingRight;
|
|
15
|
-
if (contentWidth <= 0
|
|
15
|
+
if (contentWidth <= 0) {
|
|
16
16
|
return 0;
|
|
17
17
|
}
|
|
18
18
|
|
package/ios/render/JMDBlock.h
CHANGED
|
@@ -92,6 +92,13 @@ FOUNDATION_EXPORT NSAttributedStringKey const JMDRunBackgroundAttributeName;
|
|
|
92
92
|
/// Tables: resolved column widths and per-row heights.
|
|
93
93
|
@property (nonatomic, strong) NSArray<NSNumber *> *columnWidths;
|
|
94
94
|
@property (nonatomic, strong) NSArray<NSNumber *> *rowHeights;
|
|
95
|
+
/// TextKit stacks built at measure time (storage owns the layout manager
|
|
96
|
+
/// and container); the views draw with these, so measure and draw never
|
|
97
|
+
/// disagree and text is laid out once. Text/Code: textStorage. Lists:
|
|
98
|
+
/// one per row. Tables: row-major cells.
|
|
99
|
+
@property (nonatomic, strong, nullable) NSTextStorage *textStorage;
|
|
100
|
+
@property (nonatomic, strong) NSArray<NSTextStorage *> *markerStorages;
|
|
101
|
+
@property (nonatomic, strong) NSArray<NSArray<NSTextStorage *> *> *cellStorages;
|
|
95
102
|
@end
|
|
96
103
|
|
|
97
104
|
NS_ASSUME_NONNULL_END
|
package/ios/render/JMDBlock.m
CHANGED
|
@@ -186,7 +186,7 @@ NSArray<NSDictionary *> *featureSettings(NSArray<NSString *> *variants) {
|
|
|
186
186
|
return features;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
UIFont *
|
|
189
|
+
UIFont *buildFontUncached(const ResolvedAttrs &attrs) {
|
|
190
190
|
UIFont *base;
|
|
191
191
|
if (attrs.family.length > 0) {
|
|
192
192
|
UIFontDescriptor *descriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{
|
|
@@ -228,6 +228,32 @@ UIFont *buildFont(const ResolvedAttrs &attrs) {
|
|
|
228
228
|
return font ?: base;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
// Descriptor matching (family + weight trait, especially for custom
|
|
232
|
+
// families) costs real time and runs once per text run otherwise. UIFont is
|
|
233
|
+
// immutable, NSCache is thread-safe: the layout thread and main thread share
|
|
234
|
+
// one cache.
|
|
235
|
+
UIFont *buildFont(const ResolvedAttrs &attrs) {
|
|
236
|
+
static NSCache<NSString *, UIFont *> *cache;
|
|
237
|
+
static dispatch_once_t onceToken;
|
|
238
|
+
dispatch_once(&onceToken, ^{
|
|
239
|
+
cache = [NSCache new];
|
|
240
|
+
cache.countLimit = 256;
|
|
241
|
+
});
|
|
242
|
+
NSString *key = [NSString stringWithFormat:@"%@\x1f%.2f\x1f%ld\x1f%d\x1f%@",
|
|
243
|
+
attrs.family ?: @"",
|
|
244
|
+
attrs.fontSize,
|
|
245
|
+
(long)attrs.weight,
|
|
246
|
+
attrs.italic ? 1 : 0,
|
|
247
|
+
[attrs.variants componentsJoinedByString:@","] ?: @""];
|
|
248
|
+
UIFont *cached = [cache objectForKey:key];
|
|
249
|
+
if (cached != nil) {
|
|
250
|
+
return cached;
|
|
251
|
+
}
|
|
252
|
+
UIFont *font = buildFontUncached(attrs);
|
|
253
|
+
[cache setObject:font forKey:key];
|
|
254
|
+
return font;
|
|
255
|
+
}
|
|
256
|
+
|
|
231
257
|
NSUnderlineStyle decorationMask(NSString *style) {
|
|
232
258
|
if ([style isEqualToString:@"double"]) {
|
|
233
259
|
return NSUnderlineStyleDouble;
|
|
@@ -84,12 +84,13 @@
|
|
|
84
84
|
return layout;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
// Lays text out with TextKit, not NSStringDrawing: boundingRect stops at
|
|
88
|
+
// the last line's drawn descent, dropping the bottom of the final line box
|
|
89
|
+
// under a custom lineHeight. The full box keeps overlays (spoiler covers,
|
|
90
|
+
// run background chips) from being clipped at the view's bottom edge and
|
|
91
|
+
// matches how RN's <Text> and the Android renderer measure. The returned
|
|
92
|
+
// storage owns the layout manager; views draw with the same stack.
|
|
93
|
+
- (NSTextStorage *)layoutText:(NSAttributedString *)text width:(CGFloat)width {
|
|
93
94
|
NSTextStorage *storage = [[NSTextStorage alloc] initWithAttributedString:text];
|
|
94
95
|
NSLayoutManager *layoutManager = [NSLayoutManager new];
|
|
95
96
|
NSTextContainer *container = [[NSTextContainer alloc]
|
|
@@ -98,10 +99,20 @@
|
|
|
98
99
|
[layoutManager addTextContainer:container];
|
|
99
100
|
[storage addLayoutManager:layoutManager];
|
|
100
101
|
[layoutManager ensureLayoutForTextContainer:container];
|
|
101
|
-
|
|
102
|
+
return storage;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static CGSize JMDUsedSize(NSTextStorage *storage) {
|
|
106
|
+
NSLayoutManager *layoutManager = storage.layoutManagers.firstObject;
|
|
107
|
+
const CGRect used =
|
|
108
|
+
[layoutManager usedRectForTextContainer:layoutManager.textContainers.firstObject];
|
|
102
109
|
return CGSizeMake(ceil(used.size.width), ceil(used.size.height));
|
|
103
110
|
}
|
|
104
111
|
|
|
112
|
+
- (CGSize)textSize:(NSAttributedString *)text width:(CGFloat)width {
|
|
113
|
+
return JMDUsedSize([self layoutText:text width:width]);
|
|
114
|
+
}
|
|
115
|
+
|
|
105
116
|
- (JMDMeasuredBlock *)measureBlock:(JMDBlock *)block
|
|
106
117
|
width:(CGFloat)width
|
|
107
118
|
imageSizes:(nullable NSDictionary<NSString *, NSArray<NSNumber *> *> *)imageSizes {
|
|
@@ -111,13 +122,17 @@
|
|
|
111
122
|
|
|
112
123
|
switch (block.kind) {
|
|
113
124
|
case JMDBlockKindText: {
|
|
114
|
-
|
|
125
|
+
NSTextStorage *storage = [self layoutText:block.attributedText width:width];
|
|
126
|
+
const CGSize size = JMDUsedSize(storage);
|
|
127
|
+
measured.textStorage = storage;
|
|
115
128
|
measured.height = size.height;
|
|
116
129
|
measured.textHeight = size.height;
|
|
117
130
|
break;
|
|
118
131
|
}
|
|
119
132
|
case JMDBlockKindCode: {
|
|
120
|
-
|
|
133
|
+
NSTextStorage *storage = [self layoutText:block.attributedText width:CGFLOAT_MAX];
|
|
134
|
+
const CGSize size = JMDUsedSize(storage);
|
|
135
|
+
measured.textStorage = storage;
|
|
121
136
|
measured.contentWidth = size.width;
|
|
122
137
|
measured.textHeight = size.height;
|
|
123
138
|
measured.height =
|
|
@@ -142,11 +157,14 @@
|
|
|
142
157
|
const CGFloat contentWidth = MAX(width - contentX, 1);
|
|
143
158
|
measured.contentWidth = contentWidth;
|
|
144
159
|
NSMutableArray<NSNumber *> *markerHeights = [NSMutableArray new];
|
|
160
|
+
NSMutableArray<NSTextStorage *> *markerStorages = [NSMutableArray new];
|
|
145
161
|
NSMutableArray<NSArray<JMDMeasuredBlock *> *> *rowContents = [NSMutableArray new];
|
|
146
162
|
CGFloat height = 0;
|
|
147
163
|
for (NSUInteger i = 0; i < block.rows.count; i++) {
|
|
148
164
|
JMDListRow *row = block.rows[i];
|
|
149
|
-
|
|
165
|
+
NSTextStorage *markerStorage = [self layoutText:row.marker width:block.markerWidth];
|
|
166
|
+
[markerStorages addObject:markerStorage];
|
|
167
|
+
const CGSize markerSize = JMDUsedSize(markerStorage);
|
|
150
168
|
NSMutableArray<JMDMeasuredBlock *> *content = [NSMutableArray new];
|
|
151
169
|
for (JMDBlock *child in row.content) {
|
|
152
170
|
[content addObject:[self measureBlock:child width:contentWidth imageSizes:imageSizes]];
|
|
@@ -159,6 +177,7 @@
|
|
|
159
177
|
}
|
|
160
178
|
}
|
|
161
179
|
measured.markerHeights = markerHeights;
|
|
180
|
+
measured.markerStorages = markerStorages;
|
|
162
181
|
measured.rowContents = rowContents;
|
|
163
182
|
measured.height = height;
|
|
164
183
|
break;
|
|
@@ -209,6 +228,7 @@
|
|
|
209
228
|
}
|
|
210
229
|
|
|
211
230
|
NSMutableArray<NSNumber *> *rowHeights = [NSMutableArray new];
|
|
231
|
+
NSMutableArray<NSArray<NSTextStorage *> *> *cellStorages = [NSMutableArray new];
|
|
212
232
|
CGFloat contentHeight = 0;
|
|
213
233
|
for (JMDTableRow *row in block.tableRows) {
|
|
214
234
|
JMDLayoutStyle *rowStyle = row.isHeader ? block.headerRowStyle : block.bodyRowStyle;
|
|
@@ -217,10 +237,14 @@
|
|
|
217
237
|
const CGFloat cellPadV = pad.top + pad.bottom;
|
|
218
238
|
const CGFloat rowExtra = rowStyle.borderTopWidth + rowStyle.borderBottomWidth;
|
|
219
239
|
CGFloat rowHeight = 0;
|
|
240
|
+
NSMutableArray<NSTextStorage *> *rowStorages = [NSMutableArray new];
|
|
220
241
|
for (NSUInteger column = 0; column < row.cells.count; column++) {
|
|
221
242
|
const CGFloat cellWidth = MAX(columnWidths[column] - cellPadH, 1);
|
|
222
|
-
|
|
243
|
+
NSTextStorage *storage = [self layoutText:row.cells[column] width:cellWidth];
|
|
244
|
+
[rowStorages addObject:storage];
|
|
245
|
+
rowHeight = MAX(rowHeight, JMDUsedSize(storage).height);
|
|
223
246
|
}
|
|
247
|
+
[cellStorages addObject:rowStorages];
|
|
224
248
|
rowHeight += cellPadV + rowExtra;
|
|
225
249
|
[rowHeights addObject:@(rowHeight)];
|
|
226
250
|
contentHeight += rowHeight;
|
|
@@ -235,6 +259,7 @@
|
|
|
235
259
|
|
|
236
260
|
measured.columnWidths = widths;
|
|
237
261
|
measured.rowHeights = rowHeights;
|
|
262
|
+
measured.cellStorages = cellStorages;
|
|
238
263
|
measured.contentWidth = contentWidth;
|
|
239
264
|
measured.height = contentHeight + block.layoutStyle.verticalInset;
|
|
240
265
|
break;
|
|
@@ -10,58 +10,81 @@
|
|
|
10
10
|
CGFloat _gap;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// Rebinds in place: a subview of the right kind at the same index is
|
|
14
|
+
// reused, anything else is replaced. List recycling rebinds whole trees, so
|
|
15
|
+
// the common case (same block kinds, different content) allocates nothing.
|
|
13
16
|
- (void)setBlocks:(NSArray<JMDMeasuredBlock *> *)blocks gap:(CGFloat)gap {
|
|
14
17
|
_measured = blocks;
|
|
15
18
|
_gap = gap;
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
NSArray<UIView *> *existing = self.subviews;
|
|
21
|
+
for (NSUInteger i = 0; i < blocks.count; i++) {
|
|
22
|
+
UIView *old = i < existing.count ? existing[i] : nil;
|
|
23
|
+
UIView *view = [self bindView:old to:blocks[i]];
|
|
24
|
+
if (view != old) {
|
|
25
|
+
[old removeFromSuperview];
|
|
26
|
+
[self insertSubview:view atIndex:i];
|
|
27
|
+
}
|
|
19
28
|
}
|
|
20
|
-
for (
|
|
21
|
-
[
|
|
29
|
+
for (NSUInteger i = blocks.count; i < existing.count; i++) {
|
|
30
|
+
[existing[i] removeFromSuperview];
|
|
22
31
|
}
|
|
23
32
|
[self setNeedsLayout];
|
|
24
33
|
}
|
|
25
34
|
|
|
26
|
-
- (UIView *)
|
|
35
|
+
- (UIView *)bindView:(nullable UIView *)old to:(JMDMeasuredBlock *)measured {
|
|
27
36
|
switch (measured.block.kind) {
|
|
28
37
|
case JMDBlockKindText: {
|
|
29
|
-
JMDBlockTextView *view = [
|
|
38
|
+
JMDBlockTextView *view = [old isKindOfClass:JMDBlockTextView.class]
|
|
39
|
+
? (JMDBlockTextView *)old
|
|
40
|
+
: [[JMDBlockTextView alloc] initWithFrame:CGRectZero];
|
|
30
41
|
view.host = self.host;
|
|
31
42
|
view.spoilerColor = measured.block.spoilerColor;
|
|
32
43
|
view.spoilerRadius = measured.block.spoilerRadius;
|
|
33
44
|
view.spoilerContinuous = measured.block.spoilerContinuous;
|
|
34
|
-
view
|
|
45
|
+
[view bindTextStorage:measured.textStorage];
|
|
35
46
|
return view;
|
|
36
47
|
}
|
|
37
48
|
case JMDBlockKindCode: {
|
|
38
|
-
JMDCodeBlockView *view = [
|
|
49
|
+
JMDCodeBlockView *view = [old isKindOfClass:JMDCodeBlockView.class]
|
|
50
|
+
? (JMDCodeBlockView *)old
|
|
51
|
+
: [[JMDCodeBlockView alloc] initWithFrame:CGRectZero];
|
|
39
52
|
[view bind:measured];
|
|
40
53
|
return view;
|
|
41
54
|
}
|
|
42
55
|
case JMDBlockKindQuote: {
|
|
43
|
-
JMDQuoteView *view = [
|
|
56
|
+
JMDQuoteView *view = [old isKindOfClass:JMDQuoteView.class]
|
|
57
|
+
? (JMDQuoteView *)old
|
|
58
|
+
: [[JMDQuoteView alloc] initWithFrame:CGRectZero];
|
|
44
59
|
[view bind:measured gap:_gap host:self.host];
|
|
45
60
|
return view;
|
|
46
61
|
}
|
|
47
62
|
case JMDBlockKindList: {
|
|
48
|
-
JMDListBlockView *view = [
|
|
63
|
+
JMDListBlockView *view = [old isKindOfClass:JMDListBlockView.class]
|
|
64
|
+
? (JMDListBlockView *)old
|
|
65
|
+
: [[JMDListBlockView alloc] initWithFrame:CGRectZero];
|
|
49
66
|
[view bind:measured gap:_gap host:self.host];
|
|
50
67
|
return view;
|
|
51
68
|
}
|
|
52
69
|
case JMDBlockKindDivider: {
|
|
53
|
-
UIView *view =
|
|
70
|
+
UIView *view = (old != nil && old.class == UIView.class)
|
|
71
|
+
? old
|
|
72
|
+
: [[UIView alloc] initWithFrame:CGRectZero];
|
|
54
73
|
view.backgroundColor = measured.block.dividerColor;
|
|
55
74
|
return view;
|
|
56
75
|
}
|
|
57
76
|
case JMDBlockKindImage: {
|
|
58
|
-
JMDImageView *view = [
|
|
77
|
+
JMDImageView *view = [old isKindOfClass:JMDImageView.class]
|
|
78
|
+
? (JMDImageView *)old
|
|
79
|
+
: [[JMDImageView alloc] initWithFrame:CGRectZero];
|
|
59
80
|
view.host = self.host;
|
|
60
81
|
[view bind:measured.block];
|
|
61
82
|
return view;
|
|
62
83
|
}
|
|
63
84
|
case JMDBlockKindTable: {
|
|
64
|
-
JMDTableView *view = [
|
|
85
|
+
JMDTableView *view = [old isKindOfClass:JMDTableView.class]
|
|
86
|
+
? (JMDTableView *)old
|
|
87
|
+
: [[JMDTableView alloc] initWithFrame:CGRectZero];
|
|
65
88
|
[view bind:measured host:self.host];
|
|
66
89
|
return view;
|
|
67
90
|
}
|
|
@@ -69,7 +92,6 @@
|
|
|
69
92
|
return [[UIView alloc] initWithFrame:CGRectZero];
|
|
70
93
|
}
|
|
71
94
|
|
|
72
|
-
|
|
73
95
|
// Never the hit view itself: markdown touches belong to the host component
|
|
74
96
|
// view; only nested scrollers (code blocks, tables) claim touches.
|
|
75
97
|
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
|
@@ -9,12 +9,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
9
9
|
/// hit-tests links, mentions, and spoilers by character range.
|
|
10
10
|
@interface JMDBlockTextView : UIView
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/// The bound storage's contents (nil before bind).
|
|
13
|
+
@property (nonatomic, readonly, nullable) NSAttributedString *attributedText;
|
|
13
14
|
@property (nonatomic, weak, nullable) id<JMDMarkdownHost> host;
|
|
14
15
|
@property (nonatomic, strong, nullable) UIColor *spoilerColor;
|
|
15
16
|
@property (nonatomic, assign) CGFloat spoilerRadius;
|
|
16
17
|
@property (nonatomic, assign) BOOL spoilerContinuous;
|
|
17
18
|
|
|
19
|
+
/// Binds a measure-time TextKit stack (see JMDMeasuredBlock); the view
|
|
20
|
+
/// draws with it and never lays text out itself.
|
|
21
|
+
- (void)bindTextStorage:(NSTextStorage *)storage;
|
|
22
|
+
|
|
18
23
|
/// Attributed-string attributes at a point in this view's coordinates;
|
|
19
24
|
/// nil when the point is not on a glyph. Used by the host for hit testing.
|
|
20
25
|
- (nullable NSDictionary *)attributesAtPoint:(CGPoint)point;
|