@phucprime/react-native-image-editor 1.0.0 → 1.0.2
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 +40 -161
- package/android/build.gradle +29 -12
- package/android/src/main/java/com/ahmedadeltito/photoeditor/widget/SlidingUpPanelLayout.java +1 -6
- package/android/src/main/java/ui/photoeditor/RNPhotoEditorModule.java +1 -2
- package/android/src/main/java/ui/photoeditor/RNPhotoEditorPackage.java +0 -6
- package/android/src/newarch/java/ui/photoeditor/RNPhotoEditorSpec.java +14 -0
- package/android/src/oldarch/java/ui/photoeditor/RNPhotoEditorSpec.java +19 -0
- package/ios/RNPhotoEditor.h +0 -5
- package/ios/RNPhotoEditor.m +16 -155
- package/ios/RNPhotoEditor.mm +25 -0
- package/ios/RNPhotoEditor.swift +168 -0
- package/lib/NativeRNPhotoEditor.d.ts +14 -0
- package/lib/NativeRNPhotoEditor.d.ts.map +1 -0
- package/lib/NativeRNPhotoEditor.js +5 -0
- package/lib/NativeRNPhotoEditor.js.map +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +8 -2
- package/lib/index.js.map +1 -1
- package/package.json +15 -7
- package/react-native-image-editor.podspec +1 -1
- package/src/NativeRNPhotoEditor.ts +19 -0
- package/src/index.ts +6 -4
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,
|
|
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="
|
|
18
|
+
| <img src="assets/ios.gif" width="280" /> | <img src="assets/android.gif" width="280" /> |
|
|
19
|
+
|
|
20
|
+
## Compatibility
|
|
34
21
|
|
|
35
|
-
|
|
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
|
-
|
|
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
|
|
39
|
+
### iOS
|
|
52
40
|
|
|
53
|
-
|
|
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
|
-
|
|
48
|
+
Then run `pod install`.
|
|
76
49
|
|
|
77
|
-
|
|
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
|
|
59
|
+
### Android
|
|
87
60
|
|
|
88
|
-
|
|
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
|
-
|
|
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
|
|
80
|
+
### Promise API (recommended)
|
|
123
81
|
|
|
124
82
|
```typescript
|
|
125
83
|
import { ImageEditor } from '@phucprime/react-native-image-editor';
|
|
126
84
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
|
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: (
|
|
146
|
-
|
|
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
|
-
|
|
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
|
-
|
|
|
163
|
-
|
|
|
164
|
-
| `path` | `string` | Path to the image file
|
|
165
|
-
| `
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
package/android/build.gradle
CHANGED
|
@@ -4,6 +4,10 @@ def safeExtGet(prop, fallback) {
|
|
|
4
4
|
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
def isNewArchitectureEnabled() {
|
|
8
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
buildscript {
|
|
8
12
|
// The Android Gradle plugin is only required when opening the android folder stand-alone.
|
|
9
13
|
// This avoids unnecessary downloads and potential conflicts when the library is included as a
|
|
@@ -16,19 +20,23 @@ buildscript {
|
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
dependencies {
|
|
19
|
-
classpath('com.android.tools.build:gradle:
|
|
23
|
+
classpath('com.android.tools.build:gradle:8.2.1')
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
if (isNewArchitectureEnabled()) {
|
|
29
|
+
apply plugin: 'com.facebook.react'
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
android {
|
|
25
33
|
namespace "ui.photoeditor"
|
|
26
|
-
compileSdkVersion safeExtGet('compileSdkVersion',
|
|
27
|
-
buildToolsVersion safeExtGet('buildToolsVersion', '
|
|
34
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 35)
|
|
35
|
+
buildToolsVersion safeExtGet('buildToolsVersion', '35.0.0')
|
|
28
36
|
|
|
29
37
|
defaultConfig {
|
|
30
|
-
minSdkVersion safeExtGet('minSdkVersion',
|
|
31
|
-
targetSdkVersion safeExtGet('targetSdkVersion',
|
|
38
|
+
minSdkVersion safeExtGet('minSdkVersion', 24)
|
|
39
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 35)
|
|
32
40
|
versionCode 1
|
|
33
41
|
versionName "1.0"
|
|
34
42
|
}
|
|
@@ -38,8 +46,18 @@ android {
|
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
compileOptions {
|
|
41
|
-
sourceCompatibility JavaVersion.
|
|
42
|
-
targetCompatibility JavaVersion.
|
|
49
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
50
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
sourceSets {
|
|
54
|
+
main {
|
|
55
|
+
if (isNewArchitectureEnabled()) {
|
|
56
|
+
java.srcDirs += ['src/newarch']
|
|
57
|
+
} else {
|
|
58
|
+
java.srcDirs += ['src/oldarch']
|
|
59
|
+
}
|
|
60
|
+
}
|
|
43
61
|
}
|
|
44
62
|
}
|
|
45
63
|
|
|
@@ -53,10 +71,9 @@ dependencies {
|
|
|
53
71
|
implementation 'com.facebook.react:react-native:+'
|
|
54
72
|
implementation files('libs/photo-editor-android.jar')
|
|
55
73
|
implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar'
|
|
56
|
-
implementation 'com.
|
|
57
|
-
implementation '
|
|
58
|
-
implementation '
|
|
59
|
-
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
|
74
|
+
implementation 'com.google.android.material:material:1.9.0'
|
|
75
|
+
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
76
|
+
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
|
60
77
|
implementation 'com.github.yalantis:ucrop:2.2.2-native'
|
|
61
|
-
implementation '
|
|
78
|
+
implementation 'androidx.exifinterface:exifinterface:1.3.7'
|
|
62
79
|
}
|
package/android/src/main/java/com/ahmedadeltito/photoeditor/widget/SlidingUpPanelLayout.java
CHANGED
|
@@ -25,7 +25,6 @@ import android.widget.ListView;
|
|
|
25
25
|
import android.widget.ScrollView;
|
|
26
26
|
|
|
27
27
|
import ui.photoeditor.R;
|
|
28
|
-
import com.nineoldandroids.view.animation.AnimatorProxy;
|
|
29
28
|
|
|
30
29
|
public class SlidingUpPanelLayout extends ViewGroup {
|
|
31
30
|
|
|
@@ -1150,11 +1149,7 @@ public class SlidingUpPanelLayout extends ViewGroup {
|
|
|
1150
1149
|
private void applyParallaxForCurrentSlideOffset() {
|
|
1151
1150
|
if (mParallaxOffset > 0) {
|
|
1152
1151
|
int mainViewOffset = getCurrentParallaxOffset();
|
|
1153
|
-
|
|
1154
|
-
mMainView.setTranslationY(mainViewOffset);
|
|
1155
|
-
} else {
|
|
1156
|
-
AnimatorProxy.wrap(mMainView).setTranslationY(mainViewOffset);
|
|
1157
|
-
}
|
|
1152
|
+
mMainView.setTranslationY(mainViewOffset);
|
|
1158
1153
|
}
|
|
1159
1154
|
}
|
|
1160
1155
|
|
|
@@ -9,13 +9,12 @@ import com.facebook.react.bridge.ActivityEventListener;
|
|
|
9
9
|
import com.facebook.react.bridge.BaseActivityEventListener;
|
|
10
10
|
import com.facebook.react.bridge.Callback;
|
|
11
11
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
12
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
13
12
|
import com.facebook.react.bridge.ReactMethod;
|
|
14
13
|
import com.facebook.react.bridge.ReadableArray;
|
|
15
14
|
import com.facebook.react.bridge.ReadableMap;
|
|
16
15
|
import java.util.ArrayList;
|
|
17
16
|
|
|
18
|
-
public class RNPhotoEditorModule extends
|
|
17
|
+
public class RNPhotoEditorModule extends RNPhotoEditorSpec {
|
|
19
18
|
|
|
20
19
|
private static final int PHOTO_EDITOR_REQUEST = 1;
|
|
21
20
|
private static final String E_PHOTO_EDITOR_CANCELLED = "E_PHOTO_EDITOR_CANCELLED";
|
|
@@ -9,7 +9,6 @@ import com.facebook.react.ReactPackage;
|
|
|
9
9
|
import com.facebook.react.bridge.NativeModule;
|
|
10
10
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
11
11
|
import com.facebook.react.uimanager.ViewManager;
|
|
12
|
-
import com.facebook.react.bridge.JavaScriptModule;
|
|
13
12
|
|
|
14
13
|
public class RNPhotoEditorPackage implements ReactPackage {
|
|
15
14
|
@Override
|
|
@@ -17,11 +16,6 @@ public class RNPhotoEditorPackage implements ReactPackage {
|
|
|
17
16
|
return Arrays.<NativeModule>asList(new RNPhotoEditorModule(reactContext));
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
// Deprecated from RN 0.47
|
|
21
|
-
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
|
22
|
-
return Collections.emptyList();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
19
|
@Override
|
|
26
20
|
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
|
27
21
|
return Collections.emptyList();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package ui.photoeditor;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* New Architecture spec wrapper.
|
|
7
|
+
* On New Architecture, this extends the codegen-generated NativeRNPhotoEditorSpec
|
|
8
|
+
* which provides TurboModule integration with compile-time type validation.
|
|
9
|
+
*/
|
|
10
|
+
abstract class RNPhotoEditorSpec extends NativeRNPhotoEditorSpec {
|
|
11
|
+
RNPhotoEditorSpec(ReactApplicationContext context) {
|
|
12
|
+
super(context);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package ui.photoeditor;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Callback;
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
5
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Old Architecture compatibility spec.
|
|
10
|
+
* On Old Architecture (bridge mode), this extends ReactContextBaseJavaModule directly.
|
|
11
|
+
* The concrete module (RNPhotoEditorModule) extends this class.
|
|
12
|
+
*/
|
|
13
|
+
abstract class RNPhotoEditorSpec extends ReactContextBaseJavaModule {
|
|
14
|
+
RNPhotoEditorSpec(ReactApplicationContext context) {
|
|
15
|
+
super(context);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public abstract void Edit(ReadableMap props, Callback onDone, Callback onCancel);
|
|
19
|
+
}
|
package/ios/RNPhotoEditor.h
CHANGED
package/ios/RNPhotoEditor.m
CHANGED
|
@@ -1,163 +1,24 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
1
2
|
|
|
2
|
-
#
|
|
3
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
4
|
+
#import <RNPhotoEditorSpec/RNPhotoEditorSpec.h>
|
|
5
|
+
#endif
|
|
3
6
|
|
|
7
|
+
@interface RCT_EXTERN_MODULE (RNPhotoEditor, NSObject)
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
RCT_EXTERN_METHOD(Edit : (NSDictionary *)props onDone : (RCTResponseSenderBlock)
|
|
10
|
+
onDone onCancel : (RCTResponseSenderBlock)onCancel)
|
|
6
11
|
|
|
7
|
-
|
|
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]);
|
|
37
|
-
}
|
|
38
|
-
|
|
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];
|
|
12
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
13
|
+
return YES;
|
|
160
14
|
}
|
|
161
15
|
|
|
16
|
+
@end
|
|
162
17
|
|
|
18
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
19
|
+
// Conform to the codegen-generated protocol for TurboModule support.
|
|
20
|
+
// The actual implementation is in RNPhotoEditor.swift; this declaration
|
|
21
|
+
// tells the compiler the Swift class satisfies the protocol.
|
|
22
|
+
@interface RNPhotoEditor () <NativeRNPhotoEditorSpec>
|
|
163
23
|
@end
|
|
24
|
+
#endif
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
|
|
3
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
4
|
+
#import <RNPhotoEditorSpec/RNPhotoEditorSpec.h>
|
|
5
|
+
#endif
|
|
6
|
+
|
|
7
|
+
@interface RCT_EXTERN_MODULE(RNPhotoEditor, NSObject)
|
|
8
|
+
|
|
9
|
+
RCT_EXTERN_METHOD(Edit:(NSDictionary *)props
|
|
10
|
+
onDone:(RCTResponseSenderBlock)onDone
|
|
11
|
+
onCancel:(RCTResponseSenderBlock)onCancel)
|
|
12
|
+
|
|
13
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
14
|
+
return YES;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
20
|
+
// Conform to the codegen-generated protocol for TurboModule support.
|
|
21
|
+
// The actual implementation is in RNPhotoEditor.swift; this declaration
|
|
22
|
+
// tells the compiler the Swift class satisfies the protocol.
|
|
23
|
+
@interface RNPhotoEditor () <NativeRNPhotoEditorSpec>
|
|
24
|
+
@end
|
|
25
|
+
#endif
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
/**
|
|
3
|
+
* TurboModule codegen spec for RNPhotoEditor.
|
|
4
|
+
*
|
|
5
|
+
* This spec enables proper New Architecture (Fabric + TurboModules) support
|
|
6
|
+
* with compile-time type validation. On Old Architecture, TurboModuleRegistry
|
|
7
|
+
* falls back to the NativeModules bridge automatically.
|
|
8
|
+
*/
|
|
9
|
+
export interface Spec extends TurboModule {
|
|
10
|
+
Edit(props: Object, onDone: (result: string) => void, onCancel: (result: number) => void): void;
|
|
11
|
+
}
|
|
12
|
+
declare const _default: Spec;
|
|
13
|
+
export default _default;
|
|
14
|
+
//# sourceMappingURL=NativeRNPhotoEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeRNPhotoEditor.d.ts","sourceRoot":"","sources":["../src/NativeRNPhotoEditor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;;;;;GAMG;AACH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,IAAI,CACF,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAChC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GACjC,IAAI,CAAC;CACT;;AAED,wBAAuE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeRNPhotoEditor.js","sourceRoot":"","sources":["../src/NativeRNPhotoEditor.ts"],"names":[],"mappings":";;AACA,+CAAmD;AAiBnD,kBAAe,kCAAmB,CAAC,YAAY,CAAO,eAAe,CAAC,CAAC"}
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA;;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
|
@@ -10,10 +10,16 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
}
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
13
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
17
|
exports.PhotoEditor = exports.ImageEditor = void 0;
|
|
15
|
-
const
|
|
16
|
-
|
|
18
|
+
const NativeRNPhotoEditor_1 = __importDefault(require("./NativeRNPhotoEditor"));
|
|
19
|
+
// TurboModuleRegistry.getEnforcing handles both architectures:
|
|
20
|
+
// - New Architecture: Uses TurboModule system directly
|
|
21
|
+
// - Old Architecture: Falls back to NativeModules bridge (RN 0.73+)
|
|
22
|
+
const RNPhotoEditor = NativeRNPhotoEditor_1.default;
|
|
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":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,gFAAwD;AAExD,+DAA+D;AAC/D,uDAAuD;AACvD,oEAAoE;AACpE,MAAM,aAAa,GAAG,6BAAmB,CAAC;AA4F1C,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.
|
|
3
|
+
"version": "1.0.2",
|
|
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",
|
|
@@ -49,9 +49,17 @@
|
|
|
49
49
|
],
|
|
50
50
|
"author": "phucprime",
|
|
51
51
|
"license": "Apache-2.0",
|
|
52
|
+
"codegenConfig": {
|
|
53
|
+
"name": "RNPhotoEditorSpec",
|
|
54
|
+
"type": "modules",
|
|
55
|
+
"jsSrcsDir": "src",
|
|
56
|
+
"android": {
|
|
57
|
+
"javaPackageName": "ui.photoeditor"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
52
60
|
"peerDependencies": {
|
|
53
|
-
"react": ">=
|
|
54
|
-
"react-native": ">=0.
|
|
61
|
+
"react": ">=18.2.0",
|
|
62
|
+
"react-native": ">=0.73.0"
|
|
55
63
|
},
|
|
56
64
|
"peerDependenciesMeta": {
|
|
57
65
|
"react": {
|
|
@@ -62,12 +70,12 @@
|
|
|
62
70
|
}
|
|
63
71
|
},
|
|
64
72
|
"devDependencies": {
|
|
65
|
-
"@types/react": "^18.2.0",
|
|
66
|
-
"@types/react-native": "^0.72.0",
|
|
73
|
+
"@types/react": "^18.2.0 || ^19.0.0",
|
|
67
74
|
"prettier": "^3.2.0",
|
|
75
|
+
"react-native": "0.78.2",
|
|
68
76
|
"typescript": "^5.3.0"
|
|
69
77
|
},
|
|
70
78
|
"engines": {
|
|
71
79
|
"node": ">=16.0.0"
|
|
72
80
|
}
|
|
73
|
-
}
|
|
81
|
+
}
|
|
@@ -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.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TurboModule codegen spec for RNPhotoEditor.
|
|
6
|
+
*
|
|
7
|
+
* This spec enables proper New Architecture (Fabric + TurboModules) support
|
|
8
|
+
* with compile-time type validation. On Old Architecture, TurboModuleRegistry
|
|
9
|
+
* falls back to the NativeModules bridge automatically.
|
|
10
|
+
*/
|
|
11
|
+
export interface Spec extends TurboModule {
|
|
12
|
+
Edit(
|
|
13
|
+
props: Object,
|
|
14
|
+
onDone: (result: string) => void,
|
|
15
|
+
onCancel: (result: number) => void,
|
|
16
|
+
): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('RNPhotoEditor');
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import NativeRNPhotoEditor from './NativeRNPhotoEditor';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// TurboModuleRegistry.getEnforcing handles both architectures:
|
|
4
|
+
// - New Architecture: Uses TurboModule system directly
|
|
5
|
+
// - Old Architecture: Falls back to NativeModules bridge (RN 0.73+)
|
|
6
|
+
const RNPhotoEditor = NativeRNPhotoEditor;
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Localization strings for the image editor UI.
|
|
@@ -123,8 +126,7 @@ const DEFAULT_LANGUAGES: Required<ImageEditorLanguage> = {
|
|
|
123
126
|
'To attach photos, we need to access media on your device',
|
|
124
127
|
continueTxt: 'Continue',
|
|
125
128
|
notNow: 'NOT NOW',
|
|
126
|
-
mediaAccessDeniedMsg:
|
|
127
|
-
'You denied storage access, no photos will be added.',
|
|
129
|
+
mediaAccessDeniedMsg: 'You denied storage access, no photos will be added.',
|
|
128
130
|
saveImageSucceed: 'Image saved',
|
|
129
131
|
eraserTitle: 'Eraser',
|
|
130
132
|
};
|