-
Notifications
You must be signed in to change notification settings - Fork 105
Use NSTextStorageDelegate instead of method swizzling
#520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
77 commits
Select commit
Hold shift + click to select a range
edce693
Use `NSTextStorageDelegate` instead of method swizzling
tomekzaw 1ea65e4
Fix spellcheck
tomekzaw 4214989
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 20166dd
Add singleline implementation
tomekzaw b089830
Improve multiline cleanup
tomekzaw d5cc035
Add TODO about spellcheck
tomekzaw 80c0686
Add missing imports
tomekzaw 0d57eeb
Add support for old architecture
tomekzaw 5675e04
Add #ifdef for imports
tomekzaw e1fca80
Restore original App.tsx
tomekzaw 5a1651f
Don't mix styles
tomekzaw 1b016bf
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw e9e0e60
Update Podfile.lock
tomekzaw d0ef4ef
Assert that delegate is nil
tomekzaw 8c06be0
Add comment with link to the issue
tomekzaw 9ff01d5
Reformat singleline input on `markdownStyle` change
tomekzaw 40abeba
Add nice constructors for `MarkdownTextStorageDelegate` and `Markdown…
tomekzaw 67968ec
Fix emoji not visible inside text (seriously, this took like 3 hours)
tomekzaw d377043
Fix updating `style` without updating `markdownStyle` for multiline i…
tomekzaw 6e40703
Add comments
tomekzaw 9fc1d8e
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 1fa1b54
Update Podfile.lock
tomekzaw 2518c5f
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 7b475de
Update Podfile.lock
tomekzaw 1c432fe
Fix flickering and missing formatting when toggling multiline prop
tomekzaw 2a37b85
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 7a13eac
Update Podfile.lock
tomekzaw 3a6a58a
Update Podfile.lock
tomekzaw 003ed5e
Update Podfile.lock
tomekzaw d402ca9
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 5cf9b9b
Update Podfile.lock
tomekzaw c00c440
Fix cursor position in new line after blockquote
tomekzaw 7425d76
Remove trailing whitespace
tomekzaw 511d885
Optimize updating paragraph style in typing attributes
tomekzaw ebd9813
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw b5c0e11
Remove outdated TODO
tomekzaw 8400a91
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 4b05c62
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 0c381f6
Update Podfile.lock
tomekzaw 1363312
Fix applying underline to the whole text on singleline input blur
tomekzaw 1f53ff2
Eliminate underline blinks while typing if previous text ends with a …
tomekzaw 7977d83
Introduce `applyMarkdownFormatting` method in `MarkdownTextFieldObser…
tomekzaw a3e9169
Fix underline blinks while typing after a link
tomekzaw 1fb4a00
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw edfa822
Fix zombie blockquote ribbon and indent
tomekzaw 03ec16f
Add comment
tomekzaw 4c70fba
Fix regression with spellcheck disappearing immediately
tomekzaw b503121
Fix blockquote line height on iOS
tomekzaw 63f2af2
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw ca0b10d
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw ab99a0c
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw fbefca5
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 5c80195
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 2d31525
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw ec09b0f
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 67cfbaa
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw c68ff30
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 36a5afd
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw d52f354
Merge branch 'main' into @tomekzaw/NSTextStorageDelegate
tomekzaw 28715f4
Update Podfile.lock
tomekzaw b121910
Fix cursor falling behind while typing fast in the middle of the text
tomekzaw 3f85c72
Fix cursor falling behind when text doesn't contain any emoji and `_t…
tomekzaw c30464e
Remove outdated code
tomekzaw e2cb08b
Add TODO
tomekzaw 60fa9ff
Add comment with explanation
tomekzaw 83a8bff
Remove duplicate delegate creation
tomekzaw b7d849f
Remove unnecessary key prop
tomekzaw 36ebfc9
Use `setAttributes` instead of removing custom and adding default att…
tomekzaw a55bd9c
Remove misleading comment
tomekzaw 4c25344
Use `fullRange` instead of `NSMakeRange`
tomekzaw 1c67cff
Restore emoji font family
tomekzaw 0e38ca8
Fix applying new styles on text input styles update
tomekzaw 8a57d96
Fix text view observer cleanup
tomekzaw 5cca12f
Remove TODO
tomekzaw 9220015
Remove TODO
tomekzaw e39892b
Restore original order of delegates
tomekzaw c8a6530
Restore original comment
tomekzaw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| #import <UIKit/UIKit.h> | ||
| #import <React/RCTUITextField.h> | ||
| #import <RNLiveMarkdown/RCTMarkdownUtils.h> | ||
|
|
||
| NS_ASSUME_NONNULL_BEGIN | ||
|
|
||
| @interface MarkdownTextFieldObserver : NSObject | ||
|
|
||
| - (instancetype)initWithTextField:(nonnull RCTUITextField *)textField markdownUtils:(nonnull RCTMarkdownUtils *)markdownUtils; | ||
|
|
||
| - (void)textFieldDidChange:(UITextField *)textField; | ||
|
|
||
| - (void)textFieldDidEndEditing:(UITextField *)textField; | ||
|
|
||
| @end | ||
|
|
||
| NS_ASSUME_NONNULL_END |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| #import <RNLiveMarkdown/MarkdownTextFieldObserver.h> | ||
| #import "react_native_assert.h" | ||
|
|
||
| @implementation MarkdownTextFieldObserver { | ||
| RCTUITextField *_textField; | ||
| RCTMarkdownUtils *_markdownUtils; | ||
| BOOL _active; | ||
| } | ||
|
|
||
| - (instancetype)initWithTextField:(nonnull RCTUITextField *)textField markdownUtils:(nonnull RCTMarkdownUtils *)markdownUtils | ||
| { | ||
| if ((self = [super init])) { | ||
| react_native_assert(textField != nil); | ||
| react_native_assert(markdownUtils != nil); | ||
|
|
||
| _textField = textField; | ||
| _markdownUtils = markdownUtils; | ||
| _active = YES; | ||
| } | ||
| return self; | ||
| } | ||
|
|
||
| - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context | ||
| { | ||
| if (_active && ([keyPath isEqualToString:@"text"] || [keyPath isEqualToString:@"attributedText"])) { | ||
| [self applyMarkdownFormatting]; | ||
| } | ||
| } | ||
|
|
||
| - (void)textFieldDidChange:(__unused UITextField *)textField | ||
| { | ||
| [self applyMarkdownFormatting]; | ||
| } | ||
|
|
||
| - (void)textFieldDidEndEditing:(__unused UITextField *)textField | ||
| { | ||
| // In order to prevent iOS from applying underline to the whole text if text ends with a link on blur, | ||
| // we need to update `defaultTextAttributes` which at this point doesn't contain NSUnderline attribute yet. | ||
| // It seems like the setter performs deep comparision, so we differentiate the new value using a counter, | ||
| // otherwise this trick would work only once. | ||
| static NSAttributedStringKey RCTLiveMarkdownForceUpdateAttributeName = @"RCTLiveMarkdownForceUpdate"; | ||
| static NSUInteger counter = 0; | ||
| NSMutableDictionary *defaultTextAttributes = [_textField.defaultTextAttributes mutableCopy]; | ||
| defaultTextAttributes[RCTLiveMarkdownForceUpdateAttributeName] = @(counter++); | ||
| _textField.defaultTextAttributes = defaultTextAttributes; | ||
| [self applyMarkdownFormatting]; | ||
| } | ||
|
|
||
| - (void)applyMarkdownFormatting | ||
| { | ||
| react_native_assert(_textField.defaultTextAttributes != nil); | ||
|
|
||
| if (_textField.markedTextRange != nil) { | ||
| return; // skip formatting during multi-stage input to avoid breaking internal state | ||
| } | ||
|
|
||
| NSMutableAttributedString *attributedText = [_textField.attributedText mutableCopy]; | ||
| [_markdownUtils applyMarkdownFormatting:attributedText withDefaultTextAttributes:_textField.defaultTextAttributes]; | ||
|
|
||
| UITextRange *textRange = _textField.selectedTextRange; | ||
|
|
||
| _active = NO; // prevent recursion | ||
| _textField.attributedText = attributedText; | ||
| _active = YES; | ||
|
|
||
| // Restore cursor position | ||
| [_textField setSelectedTextRange:textRange notifyDelegate:NO]; | ||
|
|
||
| // Eliminate underline blinks while typing if previous text ends with a link | ||
| _textField.typingAttributes = _textField.defaultTextAttributes; | ||
| } | ||
|
|
||
| @end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| #import <UIKit/UIKit.h> | ||
| #import <React/RCTUITextView.h> | ||
| #import <RNLiveMarkdown/RCTMarkdownUtils.h> | ||
|
|
||
| NS_ASSUME_NONNULL_BEGIN | ||
|
|
||
| @interface MarkdownTextStorageDelegate : NSObject <NSTextStorageDelegate> | ||
|
|
||
| - (instancetype)initWithTextView:(nonnull RCTUITextView *)textView markdownUtils:(nonnull RCTMarkdownUtils *)markdownUtils; | ||
|
|
||
| @end | ||
|
|
||
| NS_ASSUME_NONNULL_END |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| #import <RNLiveMarkdown/MarkdownTextStorageDelegate.h> | ||
| #import "react_native_assert.h" | ||
|
|
||
| @implementation MarkdownTextStorageDelegate { | ||
| RCTUITextView *_textView; | ||
| RCTMarkdownUtils *_markdownUtils; | ||
| } | ||
|
|
||
| - (instancetype)initWithTextView:(nonnull RCTUITextView *)textView markdownUtils:(nonnull RCTMarkdownUtils *)markdownUtils | ||
| { | ||
| if ((self = [super init])) { | ||
| react_native_assert(textView != nil); | ||
| react_native_assert(markdownUtils != nil); | ||
|
|
||
| _textView = textView; | ||
| _markdownUtils = markdownUtils; | ||
| } | ||
| return self; | ||
| } | ||
|
|
||
| - (void)textStorage:(NSTextStorage *)textStorage didProcessEditing:(NSTextStorageEditActions)editedMask range:(NSRange)editedRange changeInLength:(NSInteger)delta { | ||
| react_native_assert(_textView.defaultTextAttributes != nil); | ||
|
|
||
| [_markdownUtils applyMarkdownFormatting:textStorage withDefaultTextAttributes:_textView.defaultTextAttributes]; | ||
| } | ||
|
|
||
| @end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| #import <UIKit/UIKit.h> | ||
| #import <React/RCTUITextView.h> | ||
| #import <RNLiveMarkdown/RCTMarkdownUtils.h> | ||
|
|
||
| NS_ASSUME_NONNULL_BEGIN | ||
|
|
||
| @interface MarkdownTextViewObserver : NSObject | ||
|
|
||
| - (instancetype)initWithTextView:(nonnull RCTUITextView *)textView markdownUtils:(nonnull RCTMarkdownUtils *)markdownUtils; | ||
|
|
||
| @end | ||
|
|
||
| NS_ASSUME_NONNULL_END |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.