@phucprime/react-native-image-editor 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -1,44 +1,32 @@
1
- <p align="center">
2
- <img src="https://lh3.googleusercontent.com/dsJXfHnUx0qvZIB_80F-q0iN18eIqmx6g10bmsVN8R6nEnLQDKvJ9lXCbnPCgDEZMw=s180" width="80" />
3
- </p>
4
-
5
1
  <h1 align="center">@phucprime/react-native-image-editor</h1>
6
2
 
7
3
  <p align="center">
8
- Native image editor for React Native — crop, draw, add text, stickers, and more.
4
+ Native image editor for React Native — crop, draw, text, stickers, and more.<br/>
5
+ Supports <strong>New Architecture</strong> (Fabric + TurboModules) and the classic bridge.
9
6
  </p>
10
7
 
11
8
  <p align="center">
12
9
  <a href="https://www.npmjs.com/package/@phucprime/react-native-image-editor"><img src="https://img.shields.io/npm/v/@phucprime/react-native-image-editor.svg?style=flat-square" alt="npm version" /></a>
13
10
  <a href="https://www.npmjs.com/package/@phucprime/react-native-image-editor"><img src="https://img.shields.io/npm/dm/@phucprime/react-native-image-editor.svg?style=flat-square" alt="npm downloads" /></a>
14
11
  <a href="https://github.com/phucprime/react-native-image-editor/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/@phucprime/react-native-image-editor.svg?style=flat-square" alt="license" /></a>
15
- <a href="https://github.com/phucprime/react-native-image-editor/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs Welcome" /></a>
16
12
  </p>
17
13
 
18
14
  ---
19
15
 
20
- ## Features
21
-
22
- - **Cropping** — Resize and reframe images
23
- - **Drawing** — Freehand drawing with color picker
24
- - **Text** — Add text overlays with custom colors
25
- - **Stickers** — Add image stickers from your app resources
26
- - **Scaling & Rotating** — Transform any added element
27
- - **Saving & Sharing** — Export edited images
28
-
29
- ## Demo
30
-
31
16
  | iOS | Android |
32
17
  | :-: | :-: |
33
- | <img src="assets/ios.gif" width="300" /> | <img src="assets/android.gif" width="300" /> |
18
+ | <img src="assets/ios.gif" width="280" /> | <img src="assets/android.gif" width="280" /> |
19
+
20
+ ## Compatibility
34
21
 
35
- ## Requirements
22
+ | | Minimum | Tested |
23
+ | --- | --- | --- |
24
+ | React Native | 0.73 | **0.78.2** |
25
+ | iOS | 13.0 | 18 |
26
+ | Android | API 24 | API 35 |
27
+ | Architecture | Old Arch ✅ | **New Arch ✅** |
36
28
 
37
- | Platform | Minimum Version |
38
- | -------- | --------------- |
39
- | iOS | 13.0 |
40
- | Android | API 21 (5.0) |
41
- | React Native | >= 0.60 |
29
+ > Requires **JDK 17** and **Gradle 8.x** for Android builds.
42
30
 
43
31
  ## Installation
44
32
 
@@ -48,33 +36,18 @@ npm install @phucprime/react-native-image-editor
48
36
  yarn add @phucprime/react-native-image-editor
49
37
  ```
50
38
 
51
- ### iOS Setup
39
+ ### iOS
52
40
 
53
- 1. Add to your `ios/Podfile`:
41
+ Add to your `Podfile`:
54
42
 
55
43
  ```ruby
56
- use_native_modules!
57
-
58
- # Required: Flipper must be disabled when using iOSPhotoEditor with use_frameworks!
59
- flipper_config = FlipperConfiguration.disabled
60
-
61
44
  use_frameworks! :linkage => :static
62
45
  pod "iOSPhotoEditor", :git => "https://github.com/phucprime/photo-editor", :branch => "master"
63
-
64
- post_install do |installer|
65
- installer.pods_project.targets.each do |target|
66
- if target.name.include?('iOSPhotoEditor')
67
- target.build_configurations.each do |config|
68
- config.build_settings['SWIFT_VERSION'] = '5'
69
- end
70
- end
71
- end
72
- end
73
46
  ```
74
47
 
75
- 2. Run `pod install` in the `ios/` directory.
48
+ Then run `pod install`.
76
49
 
77
- 3. Add to `Info.plist`:
50
+ Add to `Info.plist`:
78
51
 
79
52
  ```xml
80
53
  <key>NSPhotoLibraryAddUsageDescription</key>
@@ -83,164 +56,70 @@ end
83
56
  <string>Allow access to select photos for editing</string>
84
57
  ```
85
58
 
86
- ### Android Setup
59
+ ### Android
87
60
 
88
- 1. Add JitPack repository to your root `android/build.gradle`:
61
+ Add JitPack to your root `android/build.gradle`:
89
62
 
90
63
  ```groovy
91
64
  allprojects {
92
65
  repositories {
93
- // ...existing repos...
94
66
  maven { url "https://jitpack.io" }
95
67
  }
96
68
  }
97
69
  ```
98
70
 
99
- 2. Add activities to `AndroidManifest.xml`:
71
+ Add activities to `AndroidManifest.xml`:
100
72
 
101
73
  ```xml
102
74
  <activity android:name="com.ahmedadeltito.photoeditor.PhotoEditorActivity" />
103
75
  <activity android:name="com.yalantis.ucrop.UCropActivity" />
104
76
  ```
105
77
 
106
- 3. For saving to external storage:
107
-
108
- ```xml
109
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
110
- ```
111
-
112
- 4. **JDK 17 required** (AGP 7.x is incompatible with JDK 21). Add to `android/gradle.properties`:
113
-
114
- ```properties
115
- org.gradle.java.home=/path/to/your/jdk-17
116
- ```
117
-
118
- > macOS Homebrew: `brew install openjdk@17`, then use `/opt/homebrew/Cellar/openjdk@17/<version>/libexec/openjdk.jdk/Contents/Home`
119
-
120
78
  ## Usage
121
79
 
122
- ### Promise-based (recommended)
80
+ ### Promise API (recommended)
123
81
 
124
82
  ```typescript
125
83
  import { ImageEditor } from '@phucprime/react-native-image-editor';
126
84
 
127
- try {
128
- const editedPath = await ImageEditor.edit('/path/to/image.jpg', {
129
- colors: ['#ff0000', '#00ff00', '#0000ff'],
130
- stickers: ['sticker1', 'sticker2'],
131
- });
132
- console.log('Edited image saved to:', editedPath);
133
- } catch (error) {
134
- console.log('Editor was cancelled');
135
- }
85
+ const editedPath = await ImageEditor.edit('/path/to/image.jpg', {
86
+ colors: ['#ff0000', '#00ff00', '#0000ff'],
87
+ stickers: ['sticker1', 'sticker2'],
88
+ });
136
89
  ```
137
90
 
138
- ### Callback-based
91
+ ### Callback API
139
92
 
140
93
  ```typescript
141
- import { ImageEditor } from '@phucprime/react-native-image-editor';
142
-
143
94
  ImageEditor.open({
144
95
  path: '/path/to/image.jpg',
145
- onDone: (editedPath) => {
146
- console.log('Edited image saved to:', editedPath);
147
- },
148
- onCancel: (resultCode) => {
149
- console.log('Editor cancelled with code:', resultCode);
150
- },
96
+ onDone: (path) => console.log('Saved:', path),
97
+ onCancel: () => console.log('Cancelled'),
151
98
  });
152
99
  ```
153
100
 
154
- > **Tip:** Use [react-native-fs](https://github.com/itinance/react-native-fs) to copy images into the app sandbox before editing.
155
-
156
- ## API Reference
157
-
158
- ### `ImageEditor.edit(path, options?): Promise<string>`
159
-
160
- Opens the editor and returns a promise with the edited image path.
101
+ ## Options
161
102
 
162
- | Parameter | Type | Description |
163
- | --------- | ---- | ----------- |
164
- | `path` | `string` | Path to the image file to edit |
165
- | `options` | `object` | Optional configuration (see below) |
103
+ | Property | Type | Description |
104
+ | -------- | ---- | ----------- |
105
+ | `path` | `string` | Path to the image file |
106
+ | `colors` | `string[]` | Hex colors for draw/text palette |
107
+ | `stickers` | `string[]` | Sticker image names from native resources |
108
+ | `hiddenControls` | `string[]` | Hide: `'text'` `'clear'` `'draw'` `'save'` `'share'` `'sticker'` `'crop'` |
109
+ | `languages` | `object` | UI localization strings |
166
110
 
167
- ### `ImageEditor.open(config): void`
168
-
169
- Opens the editor with callback-based API.
170
-
171
- ### Configuration
172
-
173
- | Property | Type | Default | Description |
174
- | -------- | ---- | ------- | ----------- |
175
- | `path` | `string` | *required* | Path to the image file |
176
- | `colors` | `string[]` | 13 default colors | Hex color strings for draw/text palette |
177
- | `stickers` | `string[]` | `[]` | Sticker image names from native resources |
178
- | `hiddenControls` | `EditorControl[]` | `[]` | Controls to hide: `'text'`, `'clear'`, `'draw'`, `'save'`, `'share'`, `'sticker'`, `'crop'` |
179
- | `languages` | `ImageEditorLanguage` | English defaults | UI localization strings |
180
- | `onDone` | `(path: string) => void` | — | Callback when editing completes |
181
- | `onCancel` | `(code: number) => void` | — | Callback when editing is cancelled |
111
+ > **Tip:** Use [react-native-fs](https://github.com/itinance/react-native-fs) to copy images into the app sandbox before editing.
182
112
 
183
113
  ## Stickers
184
114
 
185
- Add sticker images to your native project:
186
-
187
- - **iOS:** Add to the Resources folder
188
- - **Android:** Add to the `drawable` folder
189
-
190
- See the [Example](Example/) project for reference.
191
-
192
- ## Migrating from react-native-photo-editor
193
-
194
- ```diff
195
- - import PhotoEditor from 'react-native-photo-editor';
196
- + import { ImageEditor } from '@phucprime/react-native-image-editor';
197
-
198
- - PhotoEditor.Edit({ path: imagePath, onDone: handleDone });
199
- + ImageEditor.open({ path: imagePath, onDone: handleDone });
200
- // or use the Promise API:
201
- + const result = await ImageEditor.edit(imagePath);
202
- ```
203
-
204
- Update your iOS `Podfile`:
205
-
206
- ```diff
207
- - pod 'RNPhotoEditor', :path => '../node_modules/react-native-photo-editor'
208
- + pod 'RNImageEditor', :path => '../node_modules/@phucprime/react-native-image-editor'
209
- - pod 'iOSPhotoEditor', :git => 'https://github.com/prscX/photo-editor'
210
- + pod 'iOSPhotoEditor', :git => 'https://github.com/phucprime/photo-editor'
211
- ```
115
+ - **iOS** — Add images to the Resources folder
116
+ - **Android** — Add images to the `drawable` folder
212
117
 
213
- ## Troubleshooting
214
-
215
- ### React Native Firebase v6+
216
-
217
- If using Firebase with `use_frameworks!`, add to your `Podfile`:
218
-
219
- ```ruby
220
- $RNFirebaseAsStaticFramework = true
221
- ```
222
-
223
- ### Kotlin Metadata Version Mismatch (Gradle 8.x + RN 0.72)
224
-
225
- Add `-Xskip-metadata-version-check` to `node_modules/@react-native/gradle-plugin/build.gradle.kts`:
226
-
227
- ```kotlin
228
- tasks.withType<KotlinCompile> {
229
- kotlinOptions {
230
- freeCompilerArgs += listOf("-Xskip-metadata-version-check")
231
- }
232
- }
233
- ```
118
+ See the [Example](Example/) project for a working setup.
234
119
 
235
120
  ## Credits
236
121
 
237
- - Android Photo Editor: [eventtus/photo-editor-android](https://github.com/eventtus/photo-editor-android)
238
- - iOS Photo Editor: [eventtus/photo-editor](https://github.com/eventtus/photo-editor)
239
- - Original library: [prscX/react-native-photo-editor](https://github.com/prscX/react-native-photo-editor)
240
-
241
- ## Contributing
242
-
243
- See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
122
+ Based on [prscX/react-native-photo-editor](https://github.com/prscX/react-native-photo-editor), with photo editor SDKs by [eventtus](https://github.com/eventtus).
244
123
 
245
124
  ## License
246
125
 
@@ -16,19 +16,19 @@ buildscript {
16
16
  }
17
17
 
18
18
  dependencies {
19
- classpath('com.android.tools.build:gradle:7.4.2')
19
+ classpath('com.android.tools.build:gradle:8.2.1')
20
20
  }
21
21
  }
22
22
  }
23
23
 
24
24
  android {
25
25
  namespace "ui.photoeditor"
26
- compileSdkVersion safeExtGet('compileSdkVersion', 33)
27
- buildToolsVersion safeExtGet('buildToolsVersion', '33.0.0')
26
+ compileSdkVersion safeExtGet('compileSdkVersion', 35)
27
+ buildToolsVersion safeExtGet('buildToolsVersion', '35.0.0')
28
28
 
29
29
  defaultConfig {
30
- minSdkVersion safeExtGet('minSdkVersion', 21)
31
- targetSdkVersion safeExtGet('targetSdkVersion', 33)
30
+ minSdkVersion safeExtGet('minSdkVersion', 24)
31
+ targetSdkVersion safeExtGet('targetSdkVersion', 35)
32
32
  versionCode 1
33
33
  versionName "1.0"
34
34
  }
@@ -38,8 +38,8 @@ android {
38
38
  }
39
39
 
40
40
  compileOptions {
41
- sourceCompatibility JavaVersion.VERSION_1_8
42
- targetCompatibility JavaVersion.VERSION_1_8
41
+ sourceCompatibility JavaVersion.VERSION_17
42
+ targetCompatibility JavaVersion.VERSION_17
43
43
  }
44
44
  }
45
45
 
@@ -54,9 +54,9 @@ dependencies {
54
54
  implementation files('libs/photo-editor-android.jar')
55
55
  implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar'
56
56
  implementation 'com.nineoldandroids:library:2.4.0'
57
- implementation 'com.android.support:design:28.0.0'
58
- implementation 'com.android.support:appcompat-v7:28.0.0'
59
- implementation 'com.android.support.constraint:constraint-layout:1.0.2'
57
+ implementation 'com.google.android.material:material:1.9.0'
58
+ implementation 'androidx.appcompat:appcompat:1.6.1'
59
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
60
60
  implementation 'com.github.yalantis:ucrop:2.2.2-native'
61
- implementation 'com.android.support:exifinterface:27.1.1'
61
+ implementation 'androidx.exifinterface:exifinterface:1.3.7'
62
62
  }
@@ -6,8 +6,3 @@
6
6
  #endif
7
7
 
8
8
  #import <UIKit/UIKit.h>
9
- @import iOSPhotoEditor;
10
-
11
- @interface RNPhotoEditor : NSObject <RCTBridgeModule, PhotoEditorDelegate>
12
-
13
- @end
@@ -1,163 +1,13 @@
1
+ #import <React/RCTBridgeModule.h>
1
2
 
2
- #import "RNPhotoEditor.h"
3
+ @interface RCT_EXTERN_MODULE(RNPhotoEditor, NSObject)
3
4
 
5
+ RCT_EXTERN_METHOD(Edit:(NSDictionary *)props
6
+ onDone:(RCTResponseSenderBlock)onDone
7
+ onCancel:(RCTResponseSenderBlock)onCancel)
4
8
 
5
- @implementation RNPhotoEditor
6
-
7
- - (dispatch_queue_t)methodQueue
8
- {
9
- return dispatch_get_main_queue();
10
- }
11
- RCT_EXPORT_MODULE()
12
-
13
- NSString *_editImagePath = nil;
14
-
15
- RCTResponseSenderBlock _onDoneEditing = nil;
16
- RCTResponseSenderBlock _onCancelEditing = nil;
17
-
18
- - (void)doneEditingWithImage:(UIImage *)image {
19
- if (_onDoneEditing == nil) return;
20
-
21
- NSError* error;
22
-
23
- BOOL isPNG = [_editImagePath.pathExtension.lowercaseString isEqualToString:@"png"];
24
- NSString* path = _editImagePath;
25
-
26
- if ([path containsString:@"file://"]) {
27
- NSURL *url = [NSURL URLWithString:_editImagePath];
28
- path = url.path;
29
- }
30
-
31
- [isPNG ? UIImagePNGRepresentation(image) : UIImageJPEGRepresentation(image, 0.8) writeToFile:path options:NSDataWritingAtomic error:&error];
32
-
33
- if (error != nil)
34
- NSLog(@"write error %@", error);
35
-
36
- _onDoneEditing(@[path]);
9
+ + (BOOL)requiresMainQueueSetup {
10
+ return YES;
37
11
  }
38
12
 
39
- - (void)canceledEditing {
40
- if (_onCancelEditing == nil) return;
41
-
42
- _onCancelEditing(@[]);
43
- }
44
-
45
- RCT_EXPORT_METHOD(Edit:(nonnull NSDictionary *)props onDone:(RCTResponseSenderBlock)onDone onCancel:(RCTResponseSenderBlock)onCancel) {
46
-
47
- dispatch_async(dispatch_get_main_queue(), ^{
48
- _editImagePath = [props objectForKey: @"path"];
49
-
50
- _onDoneEditing = onDone;
51
- _onCancelEditing = onCancel;
52
-
53
- PhotoEditorViewController *photoEditor = [[PhotoEditorViewController alloc] initWithNibName:@"PhotoEditorViewController" bundle: [NSBundle bundleForClass:[PhotoEditorViewController class]]];
54
- // set language
55
- NSDictionary *languages = [props objectForKey: @"languages"];
56
- [[TranslationService shared] initTranslations:languages];
57
-
58
- // Process Image for Editing
59
- UIImage *image = [UIImage imageWithContentsOfFile:_editImagePath];
60
- if (image == nil) {
61
- NSURL *url = [NSURL URLWithString:_editImagePath];
62
- NSData *data = [NSData dataWithContentsOfURL:url];
63
-
64
- image = [UIImage imageWithData:data];
65
- }
66
-
67
- photoEditor.image = image;
68
-
69
- // Process Stickers
70
- NSArray *stickers = [props objectForKey: @"stickers"];
71
- NSMutableArray *imageStickers = [[NSMutableArray alloc] initWithCapacity:stickers.count];
72
-
73
- for (NSString *sticker in stickers) {
74
- [imageStickers addObject: [UIImage imageNamed: sticker]];
75
- }
76
-
77
- photoEditor.stickers = imageStickers;
78
-
79
- //Process Controls
80
- NSArray *hiddenControls = [props objectForKey: @"hiddenControls"];
81
- NSMutableArray *passHiddenControls = [[NSMutableArray alloc] initWithCapacity:hiddenControls.count];
82
-
83
- for (NSString *hiddenControl in hiddenControls) {
84
- [passHiddenControls addObject: [[NSString alloc] initWithString: hiddenControl]];
85
- }
86
-
87
- photoEditor.hiddenControls = passHiddenControls;
88
-
89
- //Process Colors
90
- NSArray *colors = [props objectForKey: @"colors"];
91
- NSMutableArray *passColors = [[NSMutableArray alloc] initWithCapacity:colors.count];
92
-
93
- for (NSString *color in colors) {
94
- [passColors addObject: [self colorWithHexString: color]];
95
- }
96
-
97
- photoEditor.colors = passColors;
98
-
99
- // Invoke Editor
100
- photoEditor.photoEditorDelegate = self;
101
-
102
- // The default modal presenting is page sheet in ios 13, not full screen
103
- if (@available(iOS 13, *)) {
104
- [photoEditor setModalPresentationStyle: UIModalPresentationFullScreen];
105
- }
106
-
107
- id<UIApplicationDelegate> app = [[UIApplication sharedApplication] delegate];
108
- UINavigationController *rootViewController = ((UINavigationController*) app.window.rootViewController);
109
-
110
- if (rootViewController.presentedViewController) {
111
- [rootViewController.presentedViewController presentViewController:photoEditor animated:YES completion:nil];
112
- return;
113
- }
114
-
115
- [rootViewController presentViewController:photoEditor animated:YES completion:nil];
116
- });
117
- }
118
-
119
-
120
- - (CGFloat) colorComponentFrom: (NSString *) string start: (NSUInteger) start length: (NSUInteger) length {
121
- NSString *substring = [string substringWithRange: NSMakeRange(start, length)];
122
- NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat: @"%@%@", substring, substring];
123
- unsigned hexComponent;
124
- [[NSScanner scannerWithString: fullHex] scanHexInt: &hexComponent];
125
- return hexComponent / 255.0;
126
- }
127
-
128
- - (UIColor *) colorWithHexString: (NSString *) hexString {
129
- NSString *colorString = [[hexString stringByReplacingOccurrencesOfString: @"#" withString: @""] uppercaseString];
130
- CGFloat alpha, red, blue, green;
131
- switch ([colorString length]) {
132
- case 3: // #RGB
133
- alpha = 1.0f;
134
- red = [self colorComponentFrom: colorString start: 0 length: 1];
135
- green = [self colorComponentFrom: colorString start: 1 length: 1];
136
- blue = [self colorComponentFrom: colorString start: 2 length: 1];
137
- break;
138
- case 4: // #ARGB
139
- alpha = [self colorComponentFrom: colorString start: 0 length: 1];
140
- red = [self colorComponentFrom: colorString start: 1 length: 1];
141
- green = [self colorComponentFrom: colorString start: 2 length: 1];
142
- blue = [self colorComponentFrom: colorString start: 3 length: 1];
143
- break;
144
- case 6: // #RRGGBB
145
- alpha = 1.0f;
146
- red = [self colorComponentFrom: colorString start: 0 length: 2];
147
- green = [self colorComponentFrom: colorString start: 2 length: 2];
148
- blue = [self colorComponentFrom: colorString start: 4 length: 2];
149
- break;
150
- case 8: // #AARRGGBB
151
- alpha = [self colorComponentFrom: colorString start: 0 length: 2];
152
- red = [self colorComponentFrom: colorString start: 2 length: 2];
153
- green = [self colorComponentFrom: colorString start: 4 length: 2];
154
- blue = [self colorComponentFrom: colorString start: 6 length: 2];
155
- break;
156
- default:
157
- return nil;
158
- }
159
- return [UIColor colorWithRed: red green: green blue: blue alpha: alpha];
160
- }
161
-
162
-
163
13
  @end
@@ -0,0 +1,168 @@
1
+ import Foundation
2
+ import UIKit
3
+ import iOSPhotoEditor
4
+
5
+ @objc(RNPhotoEditor)
6
+ class RNPhotoEditor: NSObject {
7
+
8
+ private var editImagePath: String?
9
+ private var onDoneEditing: RCTResponseSenderBlock?
10
+ private var onCancelEditing: RCTResponseSenderBlock?
11
+
12
+ @objc static func requiresMainQueueSetup() -> Bool {
13
+ return true
14
+ }
15
+
16
+ @objc func methodQueue() -> DispatchQueue {
17
+ return .main
18
+ }
19
+
20
+ @objc(Edit:onDone:onCancel:)
21
+ func edit(_ props: NSDictionary, onDone: @escaping RCTResponseSenderBlock, onCancel: @escaping RCTResponseSenderBlock) {
22
+ DispatchQueue.main.async { [weak self] in
23
+ guard let self = self else { return }
24
+
25
+ self.editImagePath = props["path"] as? String
26
+ self.onDoneEditing = onDone
27
+ self.onCancelEditing = onCancel
28
+
29
+ let photoEditor = PhotoEditorViewController(
30
+ nibName: "PhotoEditorViewController",
31
+ bundle: Bundle(for: PhotoEditorViewController.self)
32
+ )
33
+
34
+ // Set language translations
35
+ // TODO: Re-enable when TranslationService is added to the iOSPhotoEditor pod
36
+ // if let languages = props["languages"] as? [String: String] {
37
+ // TranslationService.shared.initTranslations(languages)
38
+ // }
39
+
40
+ // Process Image for Editing
41
+ var image: UIImage?
42
+ if let path = self.editImagePath {
43
+ image = UIImage(contentsOfFile: path)
44
+ if image == nil, let url = URL(string: path), let data = try? Data(contentsOf: url) {
45
+ image = UIImage(data: data)
46
+ }
47
+ }
48
+ photoEditor.image = image
49
+
50
+ // Process Stickers
51
+ if let stickers = props["stickers"] as? [String] {
52
+ photoEditor.stickers = stickers.compactMap { UIImage(named: $0) }
53
+ }
54
+
55
+ // Process Controls
56
+ if let hiddenControls = props["hiddenControls"] as? [String] {
57
+ photoEditor.hiddenControls = hiddenControls.compactMap { controlName in
58
+ switch controlName.lowercased() {
59
+ case "crop": return .crop
60
+ case "sticker": return .sticker
61
+ case "draw": return .draw
62
+ case "text": return .text
63
+ case "save": return .save
64
+ case "share": return .share
65
+ case "clear": return .clear
66
+ default: return nil
67
+ }
68
+ }
69
+ }
70
+
71
+ // Process Colors
72
+ if let colors = props["colors"] as? [String] {
73
+ photoEditor.colors = colors.compactMap { self.color(fromHexString: $0) }
74
+ }
75
+
76
+ // Invoke Editor
77
+ photoEditor.photoEditorDelegate = self
78
+
79
+ // The default modal presenting is page sheet in iOS 13, not full screen
80
+ photoEditor.modalPresentationStyle = .fullScreen
81
+
82
+ guard let rootViewController = UIApplication.shared.delegate?.window??.rootViewController else { return }
83
+
84
+ if let presentedVC = rootViewController.presentedViewController {
85
+ presentedVC.present(photoEditor, animated: true, completion: nil)
86
+ } else {
87
+ rootViewController.present(photoEditor, animated: true, completion: nil)
88
+ }
89
+ }
90
+ }
91
+
92
+ // MARK: - Hex Color Utilities
93
+
94
+ private func colorComponent(from string: String, start: Int, length: Int) -> CGFloat {
95
+ let startIndex = string.index(string.startIndex, offsetBy: start)
96
+ let endIndex = string.index(startIndex, offsetBy: length)
97
+ var substring = String(string[startIndex..<endIndex])
98
+ if length == 1 {
99
+ substring = "\(substring)\(substring)"
100
+ }
101
+ var hexComponent: UInt64 = 0
102
+ Scanner(string: substring).scanHexInt64(&hexComponent)
103
+ return CGFloat(hexComponent) / 255.0
104
+ }
105
+
106
+ private func color(fromHexString hexString: String) -> UIColor? {
107
+ let colorString = hexString.replacingOccurrences(of: "#", with: "").uppercased()
108
+ let alpha: CGFloat
109
+ let red: CGFloat
110
+ let green: CGFloat
111
+ let blue: CGFloat
112
+
113
+ switch colorString.count {
114
+ case 3: // #RGB
115
+ alpha = 1.0
116
+ red = colorComponent(from: colorString, start: 0, length: 1)
117
+ green = colorComponent(from: colorString, start: 1, length: 1)
118
+ blue = colorComponent(from: colorString, start: 2, length: 1)
119
+ case 4: // #ARGB
120
+ alpha = colorComponent(from: colorString, start: 0, length: 1)
121
+ red = colorComponent(from: colorString, start: 1, length: 1)
122
+ green = colorComponent(from: colorString, start: 2, length: 1)
123
+ blue = colorComponent(from: colorString, start: 3, length: 1)
124
+ case 6: // #RRGGBB
125
+ alpha = 1.0
126
+ red = colorComponent(from: colorString, start: 0, length: 2)
127
+ green = colorComponent(from: colorString, start: 2, length: 2)
128
+ blue = colorComponent(from: colorString, start: 4, length: 2)
129
+ case 8: // #AARRGGBB
130
+ alpha = colorComponent(from: colorString, start: 0, length: 2)
131
+ red = colorComponent(from: colorString, start: 2, length: 2)
132
+ green = colorComponent(from: colorString, start: 4, length: 2)
133
+ blue = colorComponent(from: colorString, start: 6, length: 2)
134
+ default:
135
+ return nil
136
+ }
137
+ return UIColor(red: red, green: green, blue: blue, alpha: alpha)
138
+ }
139
+ }
140
+
141
+ // MARK: - PhotoEditorDelegate
142
+
143
+ extension RNPhotoEditor: PhotoEditorDelegate {
144
+ func doneEditing(image: UIImage) {
145
+ guard let onDoneEditing = onDoneEditing, let editImagePath = editImagePath else { return }
146
+
147
+ let isPNG = (editImagePath as NSString).pathExtension.lowercased() == "png"
148
+ var path = editImagePath
149
+
150
+ if path.contains("file://"), let url = URL(string: editImagePath) {
151
+ path = url.path
152
+ }
153
+
154
+ let data = isPNG ? image.pngData() : image.jpegData(compressionQuality: 0.8)
155
+ do {
156
+ try data?.write(to: URL(fileURLWithPath: path), options: .atomic)
157
+ } catch {
158
+ NSLog("write error %@", error.localizedDescription)
159
+ }
160
+
161
+ onDoneEditing([path])
162
+ }
163
+
164
+ func canceledEditing() {
165
+ guard let onCancelEditing = onCancelEditing else { return }
166
+ onCancelEditing([])
167
+ }
168
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kCAAkC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kDAAkD;IAClD,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wDAAwD;AACxD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAEhC;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAuCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,cAAM,WAAW;IACf;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAgC5C;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC,GAChE,OAAO,CAAC,MAAM,CAAC;IAYlB;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;CAG7C;AAED;;GAEG;AACH,QAAA,MAAM,WAAW,oBAAc,CAAC;AAEhC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AACpC,eAAe,WAAW,CAAC;AAG3B,mDAAmD;AACnD,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AACjD,qDAAqD;AACrD,MAAM,MAAM,QAAQ,GAAG,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kCAAkC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kDAAkD;IAClD,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wDAAwD;AACxD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAEhC;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAsCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,cAAM,WAAW;IACf;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAgC5C;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC,GAChE,OAAO,CAAC,MAAM,CAAC;IAYlB;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;CAG7C;AAED;;GAEG;AACH,QAAA,MAAM,WAAW,oBAAc,CAAC;AAEhC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AACpC,eAAe,WAAW,CAAC;AAG3B,mDAAmD;AACnD,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AACjD,qDAAqD;AACrD,MAAM,MAAM,QAAQ,GAAG,mBAAmB,CAAC"}
package/lib/index.js CHANGED
@@ -13,7 +13,13 @@ var __rest = (this && this.__rest) || function (s, e) {
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.PhotoEditor = exports.ImageEditor = void 0;
15
15
  const react_native_1 = require("react-native");
16
- const { RNPhotoEditor } = react_native_1.NativeModules;
16
+ // Support both New Architecture (interop layer) and Old Architecture (NativeModules bridge).
17
+ // In RN 0.78+, NativeModules works through the TurboModule interop layer in bridgeless mode.
18
+ const RNPhotoEditor = react_native_1.NativeModules.RNPhotoEditor;
19
+ if (!RNPhotoEditor) {
20
+ throw new Error('@phucprime/react-native-image-editor: NativeModule RNPhotoEditor is null. ' +
21
+ 'Make sure the native module is properly linked.');
22
+ }
17
23
  /** Default color palette for the editor. */
18
24
  const DEFAULT_COLORS = [
19
25
  '#000000',
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,+CAAuD;AAEvD,MAAM,EAAE,aAAa,EAAE,GAAG,4BAAa,CAAC;AA4FxC,4CAA4C;AAC5C,MAAM,cAAc,GAAa;IAC/B,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,oCAAoC;AACpC,MAAM,iBAAiB,GAAkC;IACvD,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,aAAa,EAAE,WAAW;IAC1B,WAAW,EAAE,QAAQ;IACrB,YAAY,EAAE,SAAS;IACvB,iBAAiB,EAAE,cAAc;IACjC,iBAAiB,EAAE,gBAAgB;IACnC,mBAAmB,EAAE,4BAA4B;IACjD,yBAAyB,EACvB,0DAA0D;IAC5D,WAAW,EAAE,UAAU;IACvB,MAAM,EAAE,SAAS;IACjB,oBAAoB,EAClB,qDAAqD;IACvD,gBAAgB,EAAE,aAAa;IAC/B,WAAW,EAAE,QAAQ;CACtB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW;IACf;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,MAAyB;QACnC,MAAM,EACJ,QAAQ,GAAG,EAAE,EACb,cAAc,GAAG,EAAE,EACnB,MAAM,GAAG,cAAc,EACvB,SAAS,EACT,MAAM,EACN,QAAQ,KAEN,MAAM,EADL,IAAI,UACL,MAAM,EARJ,2EAQL,CAAS,CAAC;QAEX,MAAM,eAAe,GAAG,SAAS;YAC/B,CAAC,iCAAM,iBAAiB,GAAK,SAAS,EACtC,CAAC,CAAC,iBAAiB,CAAC;QAEtB,aAAa,CAAC,IAAI,iBAEd,MAAM;YACN,cAAc;YACd,QAAQ,EACR,SAAS,EAAE,eAAe,IACvB,IAAI,GAET,CAAC,SAAiB,EAAE,EAAE;YACpB,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAG,SAAS,CAAC,CAAC;QACtB,CAAC,EACD,CAAC,UAAkB,EAAE,EAAE;YACrB,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,UAAU,CAAC,CAAC;QACzB,CAAC,CACF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,CACT,IAAY,EACZ,OAAiE;QAEjE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,WAAW,CAAC,IAAI,iCACX,OAAO,KACV,IAAI,EACJ,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,CAAC,UAAU,EAAE,EAAE,CACvB,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC,IAChE,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAAyB;QACnC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;CACF;AAOQ,kCAAW;AALpB;;GAEG;AACH,MAAM,WAAW,GAAG,WAAW,CAAC;AAEV,kCAAW;AACjC,kBAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,+CAAuD;AAEvD,6FAA6F;AAC7F,6FAA6F;AAC7F,MAAM,aAAa,GAAG,4BAAa,CAAC,aAAa,CAAC;AAClD,IAAI,CAAC,aAAa,EAAE,CAAC;IACnB,MAAM,IAAI,KAAK,CACb,4EAA4E;QAC1E,iDAAiD,CACpD,CAAC;AACJ,CAAC;AA4FD,4CAA4C;AAC5C,MAAM,cAAc,GAAa;IAC/B,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,oCAAoC;AACpC,MAAM,iBAAiB,GAAkC;IACvD,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;IACjB,aAAa,EAAE,WAAW;IAC1B,WAAW,EAAE,QAAQ;IACrB,YAAY,EAAE,SAAS;IACvB,iBAAiB,EAAE,cAAc;IACjC,iBAAiB,EAAE,gBAAgB;IACnC,mBAAmB,EAAE,4BAA4B;IACjD,yBAAyB,EACvB,0DAA0D;IAC5D,WAAW,EAAE,UAAU;IACvB,MAAM,EAAE,SAAS;IACjB,oBAAoB,EAAE,qDAAqD;IAC3E,gBAAgB,EAAE,aAAa;IAC/B,WAAW,EAAE,QAAQ;CACtB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW;IACf;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,MAAyB;QACnC,MAAM,EACJ,QAAQ,GAAG,EAAE,EACb,cAAc,GAAG,EAAE,EACnB,MAAM,GAAG,cAAc,EACvB,SAAS,EACT,MAAM,EACN,QAAQ,KAEN,MAAM,EADL,IAAI,UACL,MAAM,EARJ,2EAQL,CAAS,CAAC;QAEX,MAAM,eAAe,GAAG,SAAS;YAC/B,CAAC,iCAAM,iBAAiB,GAAK,SAAS,EACtC,CAAC,CAAC,iBAAiB,CAAC;QAEtB,aAAa,CAAC,IAAI,iBAEd,MAAM;YACN,cAAc;YACd,QAAQ,EACR,SAAS,EAAE,eAAe,IACvB,IAAI,GAET,CAAC,SAAiB,EAAE,EAAE;YACpB,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAG,SAAS,CAAC,CAAC;QACtB,CAAC,EACD,CAAC,UAAkB,EAAE,EAAE;YACrB,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,UAAU,CAAC,CAAC;QACzB,CAAC,CACF,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,CACT,IAAY,EACZ,OAAiE;QAEjE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,WAAW,CAAC,IAAI,iCACX,OAAO,KACV,IAAI,EACJ,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,CAAC,UAAU,EAAE,EAAE,CACvB,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC,IAChE,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAAyB;QACnC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;CACF;AAOQ,kCAAW;AALpB;;GAEG;AACH,MAAM,WAAW,GAAG,WAAW,CAAC;AAEV,kCAAW;AACjC,kBAAe,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phucprime/react-native-image-editor",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "React Native: Native Image Editor for iOS and Android with drawing, text, stickers, cropping and more",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -31,7 +31,7 @@
31
31
  "format": "prettier --write src/",
32
32
  "clean": "rm -rf lib/",
33
33
  "prepare": "npm run clean && npm run build",
34
- "release": "npm run prepare && npm publish --access public"
34
+ "release": "npm run prepare && npm publish --access public --registry https://registry.npmjs.org/"
35
35
  },
36
36
  "keywords": [
37
37
  "react-native",
@@ -62,12 +62,12 @@
62
62
  }
63
63
  },
64
64
  "devDependencies": {
65
- "@types/react": "^18.2.0",
66
- "@types/react-native": "^0.72.0",
65
+ "@types/react": "^18.2.0 || ^19.0.0",
67
66
  "prettier": "^3.2.0",
67
+ "react-native": "0.78.2",
68
68
  "typescript": "^5.3.0"
69
69
  },
70
70
  "engines": {
71
71
  "node": ">=16.0.0"
72
72
  }
73
- }
73
+ }
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
12
12
  s.platforms = { :ios => "13.0" }
13
13
  s.source = { :git => "https://github.com/phucprime/react-native-image-editor.git", :tag => "#{s.version}" }
14
14
 
15
- s.source_files = "ios/**/*.{h,m,mm}"
15
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
16
16
  s.dependency "iOSPhotoEditor"
17
17
 
18
18
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
package/src/index.ts CHANGED
@@ -1,6 +1,14 @@
1
1
  import { NativeModules, Platform } from 'react-native';
2
2
 
3
- const { RNPhotoEditor } = NativeModules;
3
+ // Support both New Architecture (interop layer) and Old Architecture (NativeModules bridge).
4
+ // In RN 0.78+, NativeModules works through the TurboModule interop layer in bridgeless mode.
5
+ const RNPhotoEditor = NativeModules.RNPhotoEditor;
6
+ if (!RNPhotoEditor) {
7
+ throw new Error(
8
+ '@phucprime/react-native-image-editor: NativeModule RNPhotoEditor is null. ' +
9
+ 'Make sure the native module is properly linked.',
10
+ );
11
+ }
4
12
 
5
13
  /**
6
14
  * Localization strings for the image editor UI.
@@ -123,8 +131,7 @@ const DEFAULT_LANGUAGES: Required<ImageEditorLanguage> = {
123
131
  'To attach photos, we need to access media on your device',
124
132
  continueTxt: 'Continue',
125
133
  notNow: 'NOT NOW',
126
- mediaAccessDeniedMsg:
127
- 'You denied storage access, no photos will be added.',
134
+ mediaAccessDeniedMsg: 'You denied storage access, no photos will be added.',
128
135
  saveImageSucceed: 'Image saved',
129
136
  eraserTitle: 'Eraser',
130
137
  };