Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2690,7 +2690,7 @@ SPEC CHECKSUMS:
ReactAppDependencyProvider: 77a7129540c0e06ab6be9a2bcb887d3d2e594431
ReactCodegen: b62625187ce853918021a7a9178cc406e9820d56
ReactCommon: d07170f92e0e853091a70b2741b7c43f5dfdea73
ReactNativeEnriched: b11d66700889cd36c9938a825736de1929349b24
ReactNativeEnriched: ce7a893fdefce993826a3177da6811b513e26526
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: 6af5d1e0290903c82b3e0cb6836a5f898c1c4634

Expand Down
46 changes: 26 additions & 20 deletions ios/styles/BlockQuoteStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,33 @@ - (void)removeTypingAttributes {
[self removeAttributes:_input->textView.selectedRange];
}

// removing first quote line by backspacing doesn't remove typing attributes because it doesn't run textViewDidChange
// so we try guessing that a point should be deleted here
- (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text {
if([self detectStyle:_input->textView.selectedRange] &&
NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0)) &&
[text isEqualToString:@""]
if(
[self detectStyle:_input->textView.selectedRange] &&
NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0)) &&
[text isEqualToString:@""]
) {
// removing first quote line by backspacing doesn't remove typing attributes because it doesn't run textViewDidChange
// so we try guessing that a line should be deleted here
NSRange paragraphRange = [_input->textView.textStorage.string paragraphRangeForRange:_input->textView.selectedRange];
[self removeAttributes:paragraphRange];
return YES;
} else if(
[self detectStyle:_input->textView.selectedRange] &&
[text isEqualToString:@""]
) {
// other case; make sure removing all the (non newline) text from a quto line also removes the line itself
NSRange paragraphRange = [_input->textView.textStorage.string paragraphRangeForRange:range];
NSValue *nonNewlineVal = [ParagraphsUtils getNonNewlineRangesIn:_input->textView range:paragraphRange].firstObject;
if(nonNewlineVal == nullptr) {
return NO;
}
NSRange nonNewlineRange = [nonNewlineVal rangeValue];
if(NSEqualRanges(range, nonNewlineRange)) {
[self removeAttributes:range];
[TextInsertionUtils replaceText:text at:range additionalAttributes:nullptr input:_input withSelection:YES];
return YES;
}
}
return NO;
}
Expand All @@ -145,22 +162,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
NSInteger searchLocation = range.location;
if(searchLocation == _input->textView.textStorage.length) {
NSParagraphStyle *pStyle = _input->textView.typingAttributes[NSParagraphStyleAttributeName];
return [self styleCondition:pStyle :NSMakeRange(0, 0)];
}

NSRange paragraphRange = NSMakeRange(0, 0);
NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
NSParagraphStyle *paragraph = [_input->textView.textStorage
attribute:NSParagraphStyleAttributeName
atIndex:searchLocation
longestEffectiveRange: &paragraphRange
inRange:inputRange
return [OccurenceUtils detect:NSParagraphStyleAttributeName withInput:_input atIndex:range.location checkPrevious:YES
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];

return [self styleCondition:paragraph :NSMakeRange(0, 0)];
}
}

Expand Down
7 changes: 5 additions & 2 deletions ios/styles/BoldStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
UIFont *currentFontAttr = (UIFont *)_input->textView.typingAttributes[NSFontAttributeName];
return [self styleCondition:currentFontAttr :range];
return [OccurenceUtils detect:NSFontAttributeName withInput:_input atIndex:range.location checkPrevious:NO
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];
}
}

Expand Down
10 changes: 5 additions & 5 deletions ios/styles/HeadingStyleBase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
UIFont *currentFontAttr = (UIFont *)[self typedInput]->textView.typingAttributes[NSFontAttributeName];
if(currentFontAttr == nullptr) {
return false;
}
return currentFontAttr.pointSize == [self getHeadingFontSize];
return [OccurenceUtils detect:NSFontAttributeName withInput:[self typedInput] atIndex:range.location checkPrevious:YES
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];
}
}

Expand Down
7 changes: 5 additions & 2 deletions ios/styles/InlineCodeStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,11 @@ - (BOOL)detectStyle:(NSRange)range {

return detected;
} else {
UIColor *currentBgColorAttr = (UIColor *)_input->textView.typingAttributes[NSBackgroundColorAttributeName];
return [self styleCondition:currentBgColorAttr :range];
return [OccurenceUtils detect:NSBackgroundColorAttributeName withInput:_input atIndex:range.location checkPrevious:NO
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];
}
}

Expand Down
10 changes: 5 additions & 5 deletions ios/styles/ItalicStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
UIFont *currentFontAttr = (UIFont *)_input->textView.typingAttributes[NSFontAttributeName];
if(currentFontAttr == nullptr) {
return false;
}
return [currentFontAttr isItalic];
return [OccurenceUtils detect:NSFontAttributeName withInput:_input atIndex:range.location checkPrevious:NO
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];
}
}

Expand Down
46 changes: 26 additions & 20 deletions ios/styles/OrderedListStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,33 @@ - (void)removeTypingAttributes {
[self removeAttributes:_input->textView.selectedRange];
}

// removing first list point by backspacing doesn't remove typing attributes because it doesn't run textViewDidChange
// so we try guessing that a point should be deleted here
- (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text {
if([self detectStyle:_input->textView.selectedRange] &&
NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0)) &&
[text isEqualToString:@""]
if(
[self detectStyle:_input->textView.selectedRange] &&
NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0)) &&
[text isEqualToString:@""]
) {
// removing first list point by backspacing doesn't remove typing attributes because it doesn't run textViewDidChange
// so we try guessing that a point should be deleted here
NSRange paragraphRange = [_input->textView.textStorage.string paragraphRangeForRange:_input->textView.selectedRange];
[self removeAttributes:paragraphRange];
return YES;
} else if(
[self detectStyle:_input->textView.selectedRange] &&
[text isEqualToString:@""]
) {
// other case; make sure removing all the (non newline) text from a list item also removes the item itself
NSRange paragraphRange = [_input->textView.textStorage.string paragraphRangeForRange:range];
NSValue *nonNewlineVal = [ParagraphsUtils getNonNewlineRangesIn:_input->textView range:paragraphRange].firstObject;
if(nonNewlineVal == nullptr) {
return NO;
}
NSRange nonNewlineRange = [nonNewlineVal rangeValue];
if(NSEqualRanges(range, nonNewlineRange)) {
[self removeAttributes:range];
[TextInsertionUtils replaceText:text at:range additionalAttributes:nullptr input:_input withSelection:YES];
return YES;
}
}
return NO;
}
Expand Down Expand Up @@ -187,22 +204,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
NSInteger searchLocation = range.location;
if(searchLocation == _input->textView.textStorage.length) {
NSParagraphStyle *pStyle = _input->textView.typingAttributes[NSParagraphStyleAttributeName];
return [self styleCondition:pStyle :NSMakeRange(0, 0)];
}

NSRange paragraphRange = NSMakeRange(0, 0);
NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
NSParagraphStyle *paragraph = [_input->textView.textStorage
attribute:NSParagraphStyleAttributeName
atIndex:searchLocation
longestEffectiveRange: &paragraphRange
inRange:inputRange
return [OccurenceUtils detect:NSParagraphStyleAttributeName withInput:_input atIndex:range.location checkPrevious:YES
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];

return [self styleCondition:paragraph :NSMakeRange(0, 0)];
}
}

Expand Down
7 changes: 5 additions & 2 deletions ios/styles/StrikethroughStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
NSNumber *currenStrikethroughAttr = (NSNumber *)_input->textView.typingAttributes[NSStrikethroughStyleAttributeName];
return currenStrikethroughAttr != nullptr;
return [OccurenceUtils detect:NSStrikethroughStyleAttributeName withInput:_input atIndex:range.location checkPrevious:NO
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];
}
}

Expand Down
7 changes: 5 additions & 2 deletions ios/styles/UnderlineStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
NSNumber *currentUnderlineAttr = (NSNumber *)_input->textView.typingAttributes[NSUnderlineStyleAttributeName];
return [self styleCondition:currentUnderlineAttr :range];
return [OccurenceUtils detect:NSUnderlineStyleAttributeName withInput:_input atIndex:range.location checkPrevious:NO
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];
}
}

Expand Down
46 changes: 26 additions & 20 deletions ios/styles/UnorderedListStyle.mm
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,33 @@ - (void)removeTypingAttributes {
[self removeAttributes:_input->textView.selectedRange];
}

// removing first list point by backspacing doesn't remove typing attributes because it doesn't run textViewDidChange
// so we try guessing that a point should be deleted here
- (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text {
if([self detectStyle:_input->textView.selectedRange] &&
NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0)) &&
[text isEqualToString:@""]
if(
[self detectStyle:_input->textView.selectedRange] &&
NSEqualRanges(_input->textView.selectedRange, NSMakeRange(0, 0)) &&
[text isEqualToString:@""]
) {
// removing first list point by backspacing doesn't remove typing attributes because it doesn't run textViewDidChange
// so we try guessing that a point should be deleted here
NSRange paragraphRange = [_input->textView.textStorage.string paragraphRangeForRange:_input->textView.selectedRange];
[self removeAttributes:paragraphRange];
return YES;
} else if(
[self detectStyle:_input->textView.selectedRange] &&
[text isEqualToString:@""]
) {
// other case; make sure removing all the (non newline) text from a list item also removes the item itself
NSRange paragraphRange = [_input->textView.textStorage.string paragraphRangeForRange:range];
NSValue *nonNewlineVal = [ParagraphsUtils getNonNewlineRangesIn:_input->textView range:paragraphRange].firstObject;
if(nonNewlineVal == nullptr) {
return NO;
}
NSRange nonNewlineRange = [nonNewlineVal rangeValue];
if(NSEqualRanges(range, nonNewlineRange)) {
[self removeAttributes:range];
[TextInsertionUtils replaceText:text at:range additionalAttributes:nullptr input:_input withSelection:YES];
return YES;
}
}
return NO;
}
Expand Down Expand Up @@ -187,22 +204,11 @@ - (BOOL)detectStyle:(NSRange)range {
}
];
} else {
NSInteger searchLocation = range.location;
if(searchLocation == _input->textView.textStorage.length) {
NSParagraphStyle *pStyle = _input->textView.typingAttributes[NSParagraphStyleAttributeName];
return [self styleCondition:pStyle :NSMakeRange(0, 0)];
}

NSRange paragraphRange = NSMakeRange(0, 0);
NSRange inputRange = NSMakeRange(0, _input->textView.textStorage.length);
NSParagraphStyle *paragraph = [_input->textView.textStorage
attribute:NSParagraphStyleAttributeName
atIndex:searchLocation
longestEffectiveRange: &paragraphRange
inRange:inputRange
return [OccurenceUtils detect:NSParagraphStyleAttributeName withInput:_input atIndex:range.location checkPrevious:YES
withCondition:^BOOL(id _Nullable value, NSRange range) {
return [self styleCondition:value :range];
}
];

return [self styleCondition:paragraph :NSMakeRange(0, 0)];
}
}

Expand Down
6 changes: 6 additions & 0 deletions ios/utils/OccurenceUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
withInput:(EnrichedTextInputView* _Nonnull)input
inRange:(NSRange)range
withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
+ (BOOL)detect
:(NSAttributedStringKey _Nonnull)key
withInput:(EnrichedTextInputView* _Nonnull)input
atIndex:(NSUInteger)index
checkPrevious:(BOOL)check
withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition;
+ (BOOL)detectMultiple
:(NSArray<NSAttributedStringKey> *_Nonnull)keys
withInput:(EnrichedTextInputView* _Nonnull)input
Expand Down
31 changes: 31 additions & 0 deletions ios/utils/OccurenceUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,37 @@ + (BOOL)detect
return totalLength == range.length;
}

// checkPrevious flag is used for styles like lists or blockquotes
// it means that first character of paragraph will be checked instead if the detection is not in input's selected range and at the end of the input
+ (BOOL)detect
:(NSAttributedStringKey _Nonnull)key
withInput:(EnrichedTextInputView* _Nonnull)input
atIndex:(NSUInteger)index
checkPrevious:(BOOL)checkPrev
withCondition:(BOOL (NS_NOESCAPE ^_Nonnull)(id _Nullable value, NSRange range))condition
{
NSRange detectionRange = NSMakeRange(index, 0);
id attrValue;
if(NSEqualRanges(input->textView.selectedRange, detectionRange)) {
attrValue = input->textView.typingAttributes[key];
} else if(index == input->textView.textStorage.string.length) {
if(checkPrev) {
NSRange paragraphRange = [input->textView.textStorage.string paragraphRangeForRange:detectionRange];
if(paragraphRange.location == detectionRange.location) {
return NO;
} else {
return [self detect:key withInput:input inRange:NSMakeRange(paragraphRange.location, 1) withCondition:condition];
}
} else {
return NO;
}
} else {
NSRange attrRange = NSMakeRange(0, 0);
attrValue = [input->textView.textStorage attribute:key atIndex:index effectiveRange:&attrRange];
}
return condition(attrValue, NSMakeRange(index, 0));
}

+ (BOOL)detectMultiple
:(NSArray<NSAttributedStringKey> *_Nonnull)keys
withInput:(EnrichedTextInputView* _Nonnull)input
Expand Down
Loading