5353
5454using namespace facebook ::react;
5555
56+ typedef NS_OPTIONS (NSUInteger , ENRMDirtyFlags) {
57+ ENRMDirtyNone = 0 ,
58+ ENRMDirtyRecreateSegments = 1 << 0 ,
59+ ENRMDirtyForceHeight = 1 << 1 ,
60+ };
61+
5662static char kENRMSegmentFadeAnimatorKey ;
5763
5864@interface EnrichedMarkdown () <RCTEnrichedMarkdownViewProtocol, UITextViewDelegate>
@@ -67,8 +73,7 @@ @implementation EnrichedMarkdown {
6773 NSMutableArray <RCTUIView *> *_segmentViews;
6874 NSMutableArray <NSNumber *> *_segmentSignatures;
6975 ENRMSegmentViewRegistry *_segmentViewRegistry;
70- BOOL _forceRecreateSegments;
71- BOOL _forceHeightUpdateOnNextRender;
76+ ENRMDirtyFlags _dirtyFlags;
7277
7378 dispatch_queue_t _renderQueue;
7479 NSUInteger _currentRenderId;
@@ -107,8 +112,7 @@ - (instancetype)initWithFrame:(CGRect)frame
107112 _md4cFlags = [ENRMMd4cFlags defaultFlags ];
108113 _segmentViews = [NSMutableArray array ];
109114 _segmentSignatures = [NSMutableArray array ];
110- _forceRecreateSegments = NO ;
111- _forceHeightUpdateOnNextRender = NO ;
115+ _dirtyFlags = ENRMDirtyNone;
112116 [self configureSegmentViewRegistry ];
113117
114118 _renderQueue = dispatch_queue_create (" com.swmansion.enriched.markdown.container.render" , DISPATCH_QUEUE_SERIAL);
@@ -130,8 +134,7 @@ - (instancetype)initWithFrame:(CGRect)frame
130134 [strongSelf->_config setFontScaleMultiplier: strongSelf->_fontScaleObserver.effectiveFontScale];
131135 }
132136 if (strongSelf->_cachedMarkdown != nil && strongSelf->_cachedMarkdown .length > 0 ) {
133- strongSelf->_forceRecreateSegments = YES ;
134- strongSelf->_forceHeightUpdateOnNextRender = YES ;
137+ strongSelf->_dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
135138 [strongSelf renderMarkdownContent: strongSelf->_cachedMarkdown];
136139 }
137140 };
@@ -148,17 +151,15 @@ - (void)configureSegmentViewRegistry
148151 matchesView: ^BOOL (RCTUIView *view, ENRMRenderedSegment *segment) {
149152 return [view isKindOfClass: [EnrichedMarkdownInternalText class ]];
150153 }
151- createView: ^RCTUIView *(ENRMRenderedSegment *segment, BOOL animateIfStreaming ) {
154+ createView: ^RCTUIView *(ENRMRenderedSegment *segment) {
152155 EnrichedMarkdown *strongSelf = weakSelf;
153156 if (!strongSelf) {
154157 return [[RCTUIView alloc ] init ];
155158 }
156159
157160 EnrichedMarkdownInternalText *view =
158161 [strongSelf createTextViewForRenderedSegment: segment.textResult];
159- if (animateIfStreaming) {
160- [strongSelf animateTextView: view fromTailStart: 0 ];
161- }
162+ [strongSelf animateTextView: view fromTailStart: 0 ];
162163 return view;
163164 }
164165 updateView: ^(RCTUIView *view, ENRMRenderedSegment *segment) {
@@ -173,16 +174,14 @@ - (void)configureSegmentViewRegistry
173174 matchesView: ^BOOL (RCTUIView *view, ENRMRenderedSegment *segment) {
174175 return [view isKindOfClass: [TableContainerView class ]];
175176 }
176- createView: ^RCTUIView *(ENRMRenderedSegment *segment, BOOL animateIfStreaming ) {
177+ createView: ^RCTUIView *(ENRMRenderedSegment *segment) {
177178 EnrichedMarkdown *strongSelf = weakSelf;
178179 if (!strongSelf) {
179180 return [[RCTUIView alloc ] init ];
180181 }
181182
182183 TableContainerView *view = [strongSelf createTableViewForSegment: segment.tableSegment];
183- if (animateIfStreaming) {
184- [strongSelf animateBlockViewIfNeeded: view];
185- }
184+ [strongSelf animateBlockViewIfNeeded: view];
186185 return view;
187186 }
188187 updateView: ^(RCTUIView *view, ENRMRenderedSegment *segment) {
@@ -194,17 +193,15 @@ - (void)configureSegmentViewRegistry
194193 matchesView: ^BOOL (RCTUIView *view, ENRMRenderedSegment *segment) {
195194 return [view isKindOfClass: [ENRMMathContainerView class ]];
196195 }
197- createView: ^RCTUIView *(ENRMRenderedSegment *segment, BOOL animateIfStreaming ) {
196+ createView: ^RCTUIView *(ENRMRenderedSegment *segment) {
198197 EnrichedMarkdown *strongSelf = weakSelf;
199198 if (!strongSelf) {
200199 return [[RCTUIView alloc ] init ];
201200 }
202201
203202 ENRMMathContainerView *view =
204203 [strongSelf createMathViewForSegment: (ENRMMathSegment *)segment.mathSegment];
205- if (animateIfStreaming) {
206- [strongSelf animateBlockViewIfNeeded: view];
207- }
204+ [strongSelf animateBlockViewIfNeeded: view];
208205 return view;
209206 }
210207 updateView: ^(RCTUIView *view, ENRMRenderedSegment *segment) {
@@ -421,7 +418,7 @@ - (void)renderMarkdownSynchronously:(NSString *)markdownString
421418 }
422419
423420 for (ENRMRenderedSegment *segment in renderedSegments) {
424- RCTUIView *view = [_segmentViewRegistry createViewForSegment: segment animateIfStreaming: NO ];
421+ RCTUIView *view = [_segmentViewRegistry createViewForSegment: segment];
425422 [_segmentViews addObject: view];
426423 [_segmentSignatures addObject: @(segment.signature)];
427424 [self addSubview: view];
@@ -436,9 +433,9 @@ - (void)applyRenderedSegments:(NSArray *)renderedSegments renderedMarkdown:(NSSt
436433 ENRMSegmentReconciliationResult *result = [ENRMSegmentReconciler reconcileCurrentViews: _segmentViews
437434 currentSignatures: _segmentSignatures
438435 renderedSegments: renderedSegments
439- reset: _forceRecreateSegments
436+ reset: (_dirtyFlags & ENRMDirtyRecreateSegments) != 0
440437 createView: ^RCTUIView *(ENRMRenderedSegment *segment) {
441- return [self ->_segmentViewRegistry createViewForSegment: segment animateIfStreaming: YES ];
438+ return [self ->_segmentViewRegistry createViewForSegment: segment];
442439 }
443440 updateView: ^(RCTUIView *view, ENRMRenderedSegment *segment) {
444441 [self ->_segmentViewRegistry updateView: view withSegment: segment];
@@ -448,16 +445,13 @@ - (void)applyRenderedSegments:(NSArray *)renderedSegments renderedMarkdown:(NSSt
448445 matchesKind: ^BOOL (RCTUIView *view, ENRMRenderedSegment *segment) {
449446 return [self ->_segmentViewRegistry view: view matchesSegment: segment];
450447 }];
451- _forceRecreateSegments = NO ;
448+ BOOL forceHeightUpdate = (_dirtyFlags & ENRMDirtyForceHeight) != 0 ;
449+ _dirtyFlags = ENRMDirtyNone;
452450
453451 _segmentViews = result.views ;
454452 _segmentSignatures = result.signatures ;
455453
456454 if (self.bounds .size .width > 0 ) {
457- // Some prop changes recreate identical-looking segments but still change
458- // Yoga height. Request one update instead of relying on size diffing.
459- BOOL forceHeightUpdate = _forceHeightUpdateOnNextRender;
460- _forceHeightUpdateOnNextRender = NO ;
461455 [self setNeedsLayout ];
462456
463457 if (forceHeightUpdate || segmentTopologyChanged) {
@@ -631,9 +625,9 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
631625
632626 if (stylePropChanged) {
633627 [ENRMImageAttachment clearAttachmentRegistry ];
634- _forceHeightUpdateOnNextRender = YES ;
628+ _dirtyFlags |= ENRMDirtyForceHeight ;
635629 if (!markdownChanged) {
636- _forceRecreateSegments = YES ;
630+ _dirtyFlags |= ENRMDirtyRecreateSegments ;
637631 }
638632 }
639633
@@ -654,8 +648,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
654648 [_config setFontScaleMultiplier: _fontScaleObserver.effectiveFontScale];
655649 }
656650 stylePropChanged = YES ;
657- _forceRecreateSegments = YES ;
658- _forceHeightUpdateOnNextRender = YES ;
651+ _dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
659652 }
660653
661654 if (newViewProps.maxFontSizeMultiplier != oldViewProps.maxFontSizeMultiplier ) {
@@ -664,26 +657,24 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
664657 [_config setMaxFontSizeMultiplier: _maxFontSizeMultiplier];
665658 }
666659 stylePropChanged = YES ;
667- _forceRecreateSegments = YES ;
668- _forceHeightUpdateOnNextRender = YES ;
660+ _dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
669661 }
670662
671663 if (newViewProps.allowTrailingMargin != oldViewProps.allowTrailingMargin ) {
672664 _allowTrailingMargin = newViewProps.allowTrailingMargin ;
673- _forceRecreateSegments = YES ;
674- _forceHeightUpdateOnNextRender = YES ;
665+ _dirtyFlags |= ENRMDirtyRecreateSegments | ENRMDirtyForceHeight;
675666 }
676667
677668 BOOL md4cFlagsChanged = NO ;
678669 if (newViewProps.md4cFlags .underline != oldViewProps.md4cFlags .underline ) {
679670 _md4cFlags.underline = newViewProps.md4cFlags .underline ;
680671 md4cFlagsChanged = YES ;
681- _forceHeightUpdateOnNextRender = YES ;
672+ _dirtyFlags |= ENRMDirtyForceHeight ;
682673 }
683674 if (newViewProps.md4cFlags .latexMath != oldViewProps.md4cFlags .latexMath ) {
684675 _md4cFlags.latexMath = newViewProps.md4cFlags .latexMath ;
685676 md4cFlagsChanged = YES ;
686- _forceHeightUpdateOnNextRender = YES ;
677+ _dirtyFlags |= ENRMDirtyForceHeight ;
687678 }
688679 BOOL allowTrailingMarginChanged = newViewProps.allowTrailingMargin != oldViewProps.allowTrailingMargin ;
689680
@@ -692,7 +683,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
692683 BOOL streamingAnimationChanged = newViewProps.streamingAnimation != oldViewProps.streamingAnimation ;
693684 if (streamingAnimationChanged) {
694685 _streamingAnimation = newViewProps.streamingAnimation ;
695- _forceHeightUpdateOnNextRender = YES ;
686+ _dirtyFlags |= ENRMDirtyForceHeight ;
696687 if (!_streamingAnimation) {
697688 for (RCTUIView *segment in _segmentViews) {
698689 if ([segment isKindOfClass: [EnrichedMarkdownInternalText class ]]) {
0 commit comments