react-native-typerich 1.0.0 → 2.2.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.
Files changed (41) hide show
  1. package/README.md +251 -10
  2. package/ReactNativeTypeRich.podspec +41 -0
  3. package/android/src/main/java/com/typerich/TypeRichTextInputView.kt +37 -10
  4. package/android/src/main/java/com/typerich/TypeRichTextInputViewManager.kt +5 -0
  5. package/ios/TypeRichTextInputView.h +27 -7
  6. package/ios/TypeRichTextInputView.mm +809 -26
  7. package/ios/cpp/TypeRichTextInputViewComponentDescriptor.h +19 -0
  8. package/ios/cpp/TypeRichTextInputViewShadowNode.h +44 -0
  9. package/ios/cpp/TypeRichTextInputViewShadowNode.mm +110 -0
  10. package/ios/cpp/TypeRichTextInputViewState.cpp +10 -0
  11. package/ios/cpp/TypeRichTextInputViewState.h +22 -0
  12. package/ios/inputTextView/TypeRichUITextView.h +14 -0
  13. package/ios/inputTextView/TypeRichUITextView.mm +100 -0
  14. package/ios/modules/commands/TypeRichTextInputCommands.h +24 -0
  15. package/ios/modules/commands/TypeRichTextInputCommands.mm +392 -0
  16. package/ios/utils/StringUtils.h +19 -0
  17. package/ios/utils/StringUtils.mm +15 -0
  18. package/ios/utils/TextInputUtils.h +26 -0
  19. package/ios/utils/TextInputUtils.mm +58 -0
  20. package/lib/module/TypeRichTextInput.js +13 -36
  21. package/lib/module/TypeRichTextInput.js.map +1 -1
  22. package/lib/module/TypeRichTextInputNativeComponent.ts +266 -52
  23. package/lib/module/index.js +1 -0
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/module/types/TypeRichTextInput.js +4 -0
  26. package/lib/module/types/TypeRichTextInput.js.map +1 -0
  27. package/lib/typescript/src/TypeRichTextInput.d.ts +2 -22
  28. package/lib/typescript/src/TypeRichTextInput.d.ts.map +1 -1
  29. package/lib/typescript/src/TypeRichTextInputNativeComponent.d.ts +200 -14
  30. package/lib/typescript/src/TypeRichTextInputNativeComponent.d.ts.map +1 -1
  31. package/lib/typescript/src/index.d.ts +1 -1
  32. package/lib/typescript/src/index.d.ts.map +1 -1
  33. package/lib/typescript/src/types/TypeRichTextInput.d.ts +95 -0
  34. package/lib/typescript/src/types/TypeRichTextInput.d.ts.map +1 -0
  35. package/package.json +1 -1
  36. package/src/TypeRichTextInput.tsx +20 -70
  37. package/src/TypeRichTextInputNativeComponent.ts +266 -52
  38. package/src/index.tsx +1 -5
  39. package/src/types/TypeRichTextInput.tsx +116 -0
  40. package/TypeRichTextInput.podspec +0 -20
  41. package/ios/TypeRichTextInputViewManager.mm +0 -27
@@ -0,0 +1,19 @@
1
+ #pragma once
2
+ #include "TypeRichTextInputViewShadowNode.h"
3
+ #include <react/debug/react_native_assert.h>
4
+ #include <react/renderer/components/TypeRichTextInputViewSpec/Props.h>
5
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
6
+
7
+ namespace facebook::react {
8
+ class TypeRichTextInputViewComponentDescriptor final
9
+ : public ConcreteComponentDescriptor<TypeRichTextInputViewShadowNode> {
10
+ public:
11
+ using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
12
+ void adopt(ShadowNode &shadowNode) const override {
13
+ react_native_assert(
14
+ dynamic_cast<TypeRichTextInputViewShadowNode *>(&shadowNode));
15
+ ConcreteComponentDescriptor::adopt(shadowNode);
16
+ }
17
+ };
18
+
19
+ } // namespace facebook::react
@@ -0,0 +1,44 @@
1
+ #pragma once
2
+ #include "TypeRichTextInputViewState.h"
3
+ #include <jsi/jsi.h>
4
+ #include <react/renderer/components/TypeRichTextInputViewSpec/EventEmitters.h>
5
+ #include <react/renderer/components/TypeRichTextInputViewSpec/Props.h>
6
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
7
+ #include <react/renderer/core/LayoutConstraints.h>
8
+
9
+ namespace facebook::react {
10
+
11
+ JSI_EXPORT extern const char TypeRichTextInputViewComponentName[];
12
+
13
+ /*
14
+ * `ShadowNode` for <TypeRichTextInputView> component.
15
+ */
16
+ class TypeRichTextInputViewShadowNode
17
+ : public ConcreteViewShadowNode<
18
+ TypeRichTextInputViewComponentName, TypeRichTextInputViewProps,
19
+ TypeRichTextInputViewEventEmitter, TypeRichTextInputViewState> {
20
+ public:
21
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
22
+ TypeRichTextInputViewShadowNode(const ShadowNodeFragment &fragment,
23
+ const ShadowNodeFamily::Shared &family,
24
+ ShadowNodeTraits traits);
25
+ TypeRichTextInputViewShadowNode(const ShadowNode &sourceShadowNode,
26
+ const ShadowNodeFragment &fragment);
27
+ void dirtyLayoutIfNeeded();
28
+ Size
29
+ measureContent(const LayoutContext &layoutContext,
30
+ const LayoutConstraints &layoutConstraints) const override;
31
+
32
+ static ShadowNodeTraits BaseTraits() {
33
+ auto traits = ConcreteViewShadowNode::BaseTraits();
34
+ traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
35
+ traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
36
+ return traits;
37
+ }
38
+
39
+ private:
40
+ int localForceHeightRecalculationCounter_;
41
+ id setupMockTextInputView_() const;
42
+ };
43
+
44
+ } // namespace facebook::react
@@ -0,0 +1,110 @@
1
+ #import "TypeRichTextInputViewShadowNode.h"
2
+ #import "CoreText/CoreText.h"
3
+ #import <TypeRichTextInputView.h>
4
+ #import <React/RCTShadowView+Layout.h>
5
+ #import <react/utils/ManagedObjectWrapper.h>
6
+ #import <yoga/Yoga.h>
7
+ #import <React/RCTLog.h>
8
+
9
+ namespace facebook::react {
10
+
11
+ extern const char TypeRichTextInputViewComponentName[] =
12
+ "TypeRichTextInputView";
13
+
14
+ TypeRichTextInputViewShadowNode::TypeRichTextInputViewShadowNode(
15
+ const ShadowNodeFragment &fragment, const ShadowNodeFamily::Shared &family,
16
+ ShadowNodeTraits traits)
17
+ : ConcreteViewShadowNode(fragment, family, traits) {
18
+ localForceHeightRecalculationCounter_ = 0;
19
+ }
20
+
21
+ // mock input is used for the first measure calls that need to be done when the
22
+ // real input isn't defined yet
23
+ id TypeRichTextInputViewShadowNode::setupMockTextInputView_() const {
24
+ // it's rendered far away from the viewport
25
+ const int veryFarAway = 20000;
26
+ const int mockSize = 1000;
27
+ TypeRichTextInputView *mockTextInputView_ = [[TypeRichTextInputView alloc]
28
+ initWithFrame:(CGRectMake(veryFarAway, veryFarAway, mockSize, mockSize))];
29
+ const auto props = this->getProps();
30
+ mockTextInputView_.blockEmitting = YES;
31
+ [mockTextInputView_ updateProps:props oldProps:nullptr];
32
+ return mockTextInputView_;
33
+ }
34
+
35
+ TypeRichTextInputViewShadowNode::TypeRichTextInputViewShadowNode(
36
+ const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment)
37
+ : ConcreteViewShadowNode(sourceShadowNode, fragment) {
38
+ dirtyLayoutIfNeeded();
39
+ }
40
+
41
+ void TypeRichTextInputViewShadowNode::dirtyLayoutIfNeeded() {
42
+ const auto state = this->getStateData();
43
+ const int receivedCounter = state.getForceHeightRecalculationCounter();
44
+
45
+ if (receivedCounter > localForceHeightRecalculationCounter_) {
46
+ localForceHeightRecalculationCounter_ = receivedCounter;
47
+ YGNodeMarkDirty(&yogaNode_);
48
+ }
49
+ }
50
+
51
+ Size TypeRichTextInputViewShadowNode::measureContent(
52
+ const LayoutContext &layoutContext,
53
+ const LayoutConstraints &layoutConstraints) const {
54
+ const auto state = this->getStateData();
55
+ const auto componentRef = state.getComponentViewRef();
56
+ RCTInternalGenericWeakWrapper *weakWrapper =
57
+ (RCTInternalGenericWeakWrapper *)unwrapManagedObject(componentRef);
58
+
59
+ RCTLogInfo(
60
+ @"[TypeRichTextInput] minH=%f maxH=%f",
61
+ layoutConstraints.minimumSize.height,
62
+ layoutConstraints.maximumSize.height
63
+ );
64
+
65
+ if (weakWrapper != nullptr) {
66
+ id componentObject = weakWrapper.object;
67
+ TypeRichTextInputView *typedComponentObject =
68
+ (TypeRichTextInputView *)componentObject;
69
+
70
+ if (typedComponentObject != nullptr) {
71
+ __block CGSize estimatedSize;
72
+
73
+ // synchronously dispatch to main thread if needed
74
+ if ([NSThread isMainThread]) {
75
+ estimatedSize = [typedComponentObject
76
+ measureSize:layoutConstraints.maximumSize.width];
77
+ } else {
78
+ dispatch_sync(dispatch_get_main_queue(), ^{
79
+ estimatedSize = [typedComponentObject
80
+ measureSize:layoutConstraints.maximumSize.width];
81
+ });
82
+ }
83
+
84
+ return {estimatedSize.width,
85
+ MIN(estimatedSize.height, layoutConstraints.maximumSize.height)};
86
+ }
87
+ } else {
88
+ __block CGSize estimatedSize;
89
+
90
+ // synchronously dispatch to main thread if needed
91
+ if ([NSThread isMainThread]) {
92
+ TypeRichTextInputView *mockTextInputView = setupMockTextInputView_();
93
+ estimatedSize =
94
+ [mockTextInputView measureSize:layoutConstraints.maximumSize.width];
95
+ } else {
96
+ dispatch_sync(dispatch_get_main_queue(), ^{
97
+ TypeRichTextInputView *mockTextInputView = setupMockTextInputView_();
98
+ estimatedSize =
99
+ [mockTextInputView measureSize:layoutConstraints.maximumSize.width];
100
+ });
101
+ }
102
+
103
+ return {estimatedSize.width,
104
+ MIN(estimatedSize.height, layoutConstraints.maximumSize.height)};
105
+ }
106
+
107
+ return Size();
108
+ }
109
+
110
+ } // namespace facebook::react
@@ -0,0 +1,10 @@
1
+ #include "TypeRichTextInputViewState.h"
2
+
3
+ namespace facebook::react {
4
+ int TypeRichTextInputViewState::getForceHeightRecalculationCounter() const {
5
+ return forceHeightRecalculationCounter_;
6
+ }
7
+ std::shared_ptr<void> TypeRichTextInputViewState::getComponentViewRef() const {
8
+ return componentViewRef_;
9
+ }
10
+ } // namespace facebook::react
@@ -0,0 +1,22 @@
1
+ #pragma once
2
+ #include <memory>
3
+
4
+ namespace facebook::react {
5
+
6
+ class TypeRichTextInputViewState {
7
+ public:
8
+ TypeRichTextInputViewState()
9
+ : forceHeightRecalculationCounter_(0), componentViewRef_(nullptr) {}
10
+ TypeRichTextInputViewState(int counter, std::shared_ptr<void> ref) {
11
+ forceHeightRecalculationCounter_ = counter;
12
+ componentViewRef_ = ref;
13
+ }
14
+ int getForceHeightRecalculationCounter() const;
15
+ std::shared_ptr<void> getComponentViewRef() const;
16
+
17
+ private:
18
+ int forceHeightRecalculationCounter_{};
19
+ std::shared_ptr<void> componentViewRef_{};
20
+ };
21
+
22
+ } // namespace facebook::react
@@ -0,0 +1,14 @@
1
+ //
2
+ // InputTextView.h
3
+ // Pods
4
+ //
5
+ // Created by Div on 29/12/25.
6
+ //
7
+
8
+ #import <UIKit/UIKit.h>
9
+
10
+ @class TypeRichTextInputView;
11
+
12
+ @interface TypeRichUITextView : UITextView
13
+ @property (nonatomic, weak) TypeRichTextInputView *owner;
14
+ @end
@@ -0,0 +1,100 @@
1
+ //
2
+ // InputTextView.m
3
+ // ReactNativeTypeRich
4
+ //
5
+ // Created by Div on 29/12/25.
6
+ //
7
+
8
+ #import "TypeRichUITextView.h"
9
+ #import "TypeRichTextInputView.h"
10
+
11
+ @implementation TypeRichUITextView
12
+
13
+ - (void)paste:(id)sender {
14
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
15
+
16
+ if ([self.owner isDisableImagePasting] &&
17
+ pb.hasImages &&
18
+ !pb.hasStrings) {
19
+ return;
20
+ }
21
+
22
+ if (
23
+ ![self.owner isDisableImagePasting]
24
+ && pb.hasImages
25
+ ) {
26
+
27
+ UIImage *image = pb.image;
28
+ if (!image) {
29
+ [super paste:sender];
30
+ return;
31
+ }
32
+
33
+ // NSData *data = UIImagePNGRepresentation(image); // when the requirement is for transparency enable this
34
+ NSData *data = UIImageJPEGRepresentation(image, 0.8);
35
+
36
+ if (!data) {
37
+ return;
38
+ }
39
+
40
+ NSString *fileName =
41
+ [NSString stringWithFormat:@"typerich_%@.png", NSUUID.UUID.UUIDString];
42
+
43
+ NSString *path =
44
+ [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
45
+
46
+ NSError *error = nil;
47
+ if (![data writeToFile:path options:NSDataWritingAtomic error:&error]) {
48
+ return;
49
+ }
50
+
51
+ [self.owner emitPasteImageEventWith:path
52
+ type:@"image/png"
53
+ fileName:fileName
54
+ fileSize:data.length];
55
+
56
+ // Prevent attachment insertion
57
+ return;
58
+ }
59
+
60
+ [super paste:sender];
61
+ }
62
+
63
+
64
+ - (BOOL)canPasteItemProviders:(NSArray<NSItemProvider *> *)itemProviders {
65
+ for (NSItemProvider *provider in itemProviders) {
66
+ if ([provider hasItemConformingToTypeIdentifier:@"public.text"]) {
67
+ return YES;
68
+ }
69
+
70
+ if (![self.owner isDisableImagePasting] &&
71
+ [provider hasItemConformingToTypeIdentifier:@"public.image"]) {
72
+ return YES;
73
+ }
74
+ }
75
+ return NO;
76
+ }
77
+
78
+ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
79
+ if (action == @selector(paste:)) {
80
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
81
+
82
+ if (
83
+ [self.owner isDisableImagePasting] &&
84
+ pb.hasImages &&
85
+ !pb.hasStrings) {
86
+ return NO;
87
+ }
88
+
89
+ // Allow paste if there is text OR image
90
+ if (pb.hasStrings || pb.hasImages) {
91
+ return YES;
92
+ }
93
+ return NO;
94
+ }
95
+
96
+ return [super canPerformAction:action withSender:sender];
97
+ }
98
+
99
+ @end
100
+
@@ -0,0 +1,24 @@
1
+ //
2
+ // TypeRichTextInputCommands.h
3
+ // Pods
4
+ //
5
+ // Created by Div on 29/12/25.
6
+ //
7
+
8
+ #import <UIKit/UIKit.h>
9
+ #import "TypeRichTextInputView.h"
10
+
11
+ @interface TypeRichTextInputCommands : NSObject
12
+ @property (nonatomic, strong) NSOperationQueue *commandQueue;
13
+
14
+ - (instancetype)initWithTextView:(UITextView *)textView
15
+ owner:(TypeRichTextInputView *)owner;
16
+
17
+ - (void)focus;
18
+ - (void)blur;
19
+ - (void)setText:(NSString *)text;
20
+ - (void)setSelectionStart:(NSInteger)start end:(NSInteger)end;
21
+ - (void)insertTextAtStart:(NSInteger)start
22
+ end:(NSInteger)end
23
+ text:(NSString *)text;
24
+ @end