@imgly/editor-react-native 1.40.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 (48) hide show
  1. package/IMGLYEditorModule.podspec +21 -0
  2. package/LICENSE.md +137 -0
  3. package/README.md +31 -0
  4. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  5. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  6. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  7. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  8. package/android/.gradle/8.9/gc.properties +0 -0
  9. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  10. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  11. package/android/.gradle/vcs-1/gc.properties +0 -0
  12. package/android/build.gradle +65 -0
  13. package/android/src/main/AndroidManifest.xml +8 -0
  14. package/android/src/main/assets/photo-ui-empty.png +0 -0
  15. package/android/src/main/kotlin/ly/img/editor/reactnative/module/IMGLYEditorModule.kt +252 -0
  16. package/android/src/main/kotlin/ly/img/editor/reactnative/module/IMGLYEditorPackage.kt +35 -0
  17. package/android/src/main/kotlin/ly/img/editor/reactnative/module/activity/EditorActivity.kt +112 -0
  18. package/android/src/main/kotlin/ly/img/editor/reactnative/module/builder/EditorBuilder.kt +478 -0
  19. package/android/src/main/kotlin/ly/img/editor/reactnative/module/helper/AssetHelper.kt +18 -0
  20. package/android/src/main/kotlin/ly/img/editor/reactnative/module/helper/IntentHelper.kt +61 -0
  21. package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorPreset.kt +47 -0
  22. package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorResult.kt +73 -0
  23. package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorSettings.kt +63 -0
  24. package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorSourceType.kt +39 -0
  25. package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/Source.kt +44 -0
  26. package/android/src/newarch/IMGLYEditorModuleSpec.kt +7 -0
  27. package/android/src/oldarch/IMGLYEditorModuleSpec.kt +18 -0
  28. package/index.d.ts +3 -0
  29. package/index.js +3 -0
  30. package/ios/Constants/IMGLYConstants.h +13 -0
  31. package/ios/Constants/IMGLYConstants.m +13 -0
  32. package/ios/Extensions/OnCreate+.swift +75 -0
  33. package/ios/Extensions/OnExport+.swift +64 -0
  34. package/ios/Extensions/String+.swift +7 -0
  35. package/ios/Helper/ExportHelper.swift +67 -0
  36. package/ios/IMGLYEditorModule-Bridging-Header.h +3 -0
  37. package/ios/IMGLYEditorModule.h +11 -0
  38. package/ios/IMGLYEditorModule.mm +86 -0
  39. package/ios/IMGLYEditorModule.swift +110 -0
  40. package/ios/Model/EditorBuilder.swift +293 -0
  41. package/ios/Model/EditorPreset.swift +52 -0
  42. package/ios/Model/EditorResult.swift +27 -0
  43. package/ios/Model/EditorSettings.swift +33 -0
  44. package/ios/Model/EditorSourceType.swift +11 -0
  45. package/ios/Model/Source.swift +8 -0
  46. package/ios/View/ModalEditor.swift +55 -0
  47. package/package.json +46 -0
  48. package/src/NativeIMGLYEditor.ts +195 -0
@@ -0,0 +1,110 @@
1
+ import UIKit
2
+
3
+ /// The iOS implementation for the `@imgly/editor-react-native` React Native module.
4
+ @objc(IMGLYEditorModuleSwiftAdapter) @objcMembers public class IMGLYEditorModuleSwiftAdapter: NSObject {
5
+ // MARK: - Typealias
6
+
7
+ /// A closure to specify an `EditorBuilder.Builder` based on a given `preset` and `metadata`.
8
+ public typealias IMGLYBuilderClosure = (_ preset: EditorPreset?, _ metadata: [String: Any]?) -> EditorBuilder.Builder
9
+
10
+ // MARK: - Properties
11
+
12
+ /// The shared instance.
13
+ public static var shared = IMGLYEditorModuleSwiftAdapter()
14
+
15
+ /// The `IMGLYBuilderClosure` to use for UI creation.
16
+ public var builderClosure: IMGLYBuilderClosure?
17
+
18
+ /// The `UIViewController` hosting the editor.
19
+ private var presentationController: UIViewController?
20
+
21
+ /// The current `EditorBuilder.EditorBuilderResult`.
22
+ private var currentResultHandler: EditorBuilder.EditorBuilderResult?
23
+
24
+ // MARK: - Editor
25
+
26
+ /// Opens the creative editor.
27
+ /// - Parameters:
28
+ /// - preset: The `EditorPreset` used to determine which UI preset to use.
29
+ /// - settings: The `EditorSettings` containing all relevant information for the editor.
30
+ /// - metadata: Any custom metadata used for the `EditorBuilder.Builder`.
31
+ /// - completion: The completion handler to execute once the editor failed, cancelled or exported.
32
+ public func openEditor(
33
+ _ preset: EditorPreset,
34
+ settings: EditorSettings,
35
+ metadata: [String: Any]?,
36
+ completion: @escaping (_ result: EditorResult?, _ error: NSError?) -> Void
37
+ ) {
38
+ _openEditor(preset, settings: settings, metadata: metadata, completion: completion)
39
+ }
40
+
41
+ /// Opens the creative editor.
42
+ /// - Parameters:
43
+ /// - settings: The `EditorSettings` containing all relevant information for the editor.
44
+ /// - metadata: Any custom metadata used for the `EditorBuilder.Builder`.
45
+ /// - completion: The completion handler to execute once the editor failed, cancelled or exported.
46
+ public func openEditor(
47
+ settings: EditorSettings,
48
+ metadata: [String: Any]?,
49
+ completion: @escaping (_ result: EditorResult?, _ error: NSError?) -> Void
50
+ ) {
51
+ _openEditor(nil, settings: settings, metadata: metadata, completion: completion)
52
+ }
53
+
54
+ private func _openEditor(
55
+ _ preset: EditorPreset?,
56
+ settings: EditorSettings,
57
+ metadata: [String: Any]?,
58
+ completion: @escaping (_ result: EditorResult?, _ error: NSError?) -> Void
59
+ ) {
60
+ let builder = builderClosure?(preset, metadata) ?? builderForPreset(preset)
61
+ // Assign the `currentResultHandler` in order to manage the calls to the completion handler.
62
+ currentResultHandler = { [weak self] result in
63
+ switch result {
64
+ case let .success(artifact):
65
+ completion(artifact, nil)
66
+ case let .failure(error):
67
+ completion(nil, error as NSError)
68
+ }
69
+ // Remove the handler to prevent multiple invokations.
70
+ self?.currentResultHandler = nil
71
+ self?.presentationController?.presentingViewController?.dismiss(animated: true)
72
+ }
73
+
74
+ presentationController = builder(settings, preset, metadata) { [weak self] result in
75
+ self?.currentResultHandler?(result)
76
+ }
77
+ presentationController?.modalPresentationStyle = .fullScreen
78
+
79
+ if let presentationController, let windowScene = UIApplication.shared.connectedScenes
80
+ .filter({ $0.activationState == .foregroundActive })
81
+ .first as? UIWindowScene {
82
+ if let rootViewController = windowScene.windows
83
+ .filter(\.isKeyWindow).first?.rootViewController {
84
+ rootViewController.present(presentationController, animated: true, completion: nil)
85
+ }
86
+ }
87
+ }
88
+
89
+ // MARK: - Helpers
90
+
91
+ /// Returns the suitable `EditorBuilder.Builder` for a given `EditorPreset`.
92
+ /// - Parameter preset: The `EditorPreset`.
93
+ /// - Returns: The suitable `EditorBuilder.Builder`. Defaults to `EditorPreset.design`.
94
+ private func builderForPreset(_ preset: EditorPreset?) -> EditorBuilder.Builder {
95
+ switch preset {
96
+ case .apparel:
97
+ EditorBuilder.apparel()
98
+ case .postcard:
99
+ EditorBuilder.postcard()
100
+ case .photo:
101
+ EditorBuilder.photo()
102
+ case .video:
103
+ EditorBuilder.video()
104
+ case .design:
105
+ EditorBuilder.design()
106
+ default:
107
+ EditorBuilder.design()
108
+ }
109
+ }
110
+ }
@@ -0,0 +1,293 @@
1
+ import IMGLYApparelEditor
2
+ import IMGLYDesignEditor
3
+ import IMGLYPhotoEditor
4
+ import IMGLYPostcardEditor
5
+ import IMGLYVideoEditor
6
+ import SwiftUI
7
+ import UIKit
8
+
9
+ /// The `EditorBuilder` is used to build different editor configurations.
10
+ public enum EditorBuilder {
11
+ /// A closure used to return a `Result<EditorResult?, Error>` from the editor.
12
+ public typealias EditorBuilderResult = (Result<EditorResult?, Error>) -> Void
13
+
14
+ /// Closure allowing to return a custom UI based on various input.
15
+ /// - Parameters:
16
+ /// - settings: The `EditorSettings`.
17
+ /// - preset: The `EditorPreset` pointing to a prebuild UI configuration.
18
+ /// - metadata: The metadata.
19
+ /// - result: The `EditorBuilderResult` used to return a result.
20
+ /// - Returns: A `UIViewController`.
21
+ public typealias Builder = (
22
+ _ settings: EditorSettings,
23
+ _ preset: EditorPreset?,
24
+ _ metadata: [String: Any]?,
25
+ _ result: @escaping EditorBuilderResult
26
+ ) -> UIViewController
27
+
28
+ /// The default apparel editor.
29
+ public static func apparel() -> Builder {
30
+ { config, _, _, result in
31
+ @ViewBuilder func apparelEditor(settings _: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
32
+ ModalApparelEditor(settings: config, result: result)
33
+ }
34
+ return UIHostingController(rootView: apparelEditor(settings: config, result: result))
35
+ }
36
+ }
37
+
38
+ /// The default postcard editor.
39
+ public static func postcard() -> Builder {
40
+ { config, _, _, result in
41
+ @ViewBuilder func postcardEditor(settings _: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
42
+ ModalPostcardEditor(settings: config, result: result)
43
+ }
44
+ return UIHostingController(rootView: postcardEditor(settings: config, result: result))
45
+ }
46
+ }
47
+
48
+ /// The default design editor.
49
+ public static func design() -> Builder {
50
+ { settings, _, _, result in
51
+ @ViewBuilder func designEditor(settings: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
52
+ ModalDesignEditor(settings: settings, result: result)
53
+ }
54
+ return UIHostingController(rootView: designEditor(settings: settings, result: result))
55
+ }
56
+ }
57
+
58
+ /// The default photo editor.
59
+ public static func photo() -> Builder {
60
+ { settings, _, _, result in
61
+ @ViewBuilder func photoEditor(settings: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
62
+ ModalPhotoEditor(settings: settings, result: result)
63
+ }
64
+ return UIHostingController(rootView: photoEditor(settings: settings, result: result))
65
+ }
66
+ }
67
+
68
+ /// The default video editor.
69
+ public static func video() -> Builder {
70
+ { settings, _, _, result in
71
+ @ViewBuilder func videoEditor(settings: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
72
+ ModalVideoEditor(settings: settings, result: result)
73
+ }
74
+ return UIHostingController(rootView: videoEditor(settings: settings, result: result))
75
+ }
76
+ }
77
+
78
+ /// A custom editor implementation.
79
+ /// - Parameter contentProvider:
80
+ /// - Returns: A `Builder` providing the custom view.
81
+ public static func custom(_ contentProvider: @escaping (
82
+ _ settings: EditorSettings,
83
+ _ preset: EditorPreset?,
84
+ _ metadata: [String: Any]?,
85
+ _ result: @escaping EditorBuilderResult
86
+ ) -> some View) -> Builder {
87
+ { settings, preset, metadata, result in
88
+ let hostingController = UIHostingController(rootView: contentProvider(settings, preset, metadata, result))
89
+ return hostingController
90
+ }
91
+ }
92
+ }
93
+
94
+ // MARK: - Custom
95
+
96
+ /// An extension for the editor views.
97
+ extension EditorBuilder {
98
+ /// The message to send if the native error has been dismissed after throwing an error.
99
+ private static let exportFailedMessage =
100
+ "Failed to initialize the editor. Please verify that the loaded license is correct."
101
+
102
+ /// Generates `EngineSettings` based on an `EditorSettings`.
103
+ /// - Parameter settings: The `EditorSettings`.
104
+ /// - Returns: The derived `EngineSettings`.
105
+ private static func engineSettings(for settings: EditorSettings) -> EngineSettings {
106
+ if let url = URL(string: settings.sceneBaseUri) {
107
+ EngineSettings(license: settings.license, userID: settings.userId, baseURL: url)
108
+ } else {
109
+ EngineSettings(license: settings.license, userID: settings.userId)
110
+ }
111
+ }
112
+
113
+ /// A modal apparel editor handling native errors.
114
+ private struct ModalApparelEditor: View {
115
+ @Environment(\.dismiss) private var dismiss
116
+ private let settings: EditorSettings
117
+ private let result: EditorBuilderResult
118
+
119
+ init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
120
+ self.settings = settings
121
+ self.result = result
122
+ }
123
+
124
+ var body: some View {
125
+ ModalEditor {
126
+ ApparelEditor(engineSettings(for: settings))
127
+ .imgly.onCreate { engine in
128
+ try await OnCreate.load(settings, defaultSource: ApparelEditor.defaultScene)(engine)
129
+ }
130
+ .imgly.onExport { engine, _ in
131
+ do {
132
+ let editorResult = try await OnExport.export(engine, .pdf)
133
+ result(.success(editorResult))
134
+ } catch {
135
+ result(.failure(error))
136
+ }
137
+ }
138
+ } onDismiss: { cancelled in
139
+ if cancelled {
140
+ result(.success(nil))
141
+ dismiss()
142
+ } else {
143
+ result(.failure(exportFailedMessage))
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ /// A modal postcard editor handling native errors.
150
+ private struct ModalPostcardEditor: View {
151
+ @Environment(\.dismiss) private var dismiss
152
+ private let settings: EditorSettings
153
+ private let result: EditorBuilderResult
154
+
155
+ init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
156
+ self.settings = settings
157
+ self.result = result
158
+ }
159
+
160
+ var body: some View {
161
+ ModalEditor {
162
+ PostcardEditor(engineSettings(for: settings))
163
+ .imgly.onCreate { engine in
164
+ try await OnCreate.load(settings, defaultSource: PostcardEditor.defaultScene)(engine)
165
+ }
166
+ .imgly.onExport { engine, _ in
167
+ do {
168
+ let editorResult = try await OnExport.export(engine, .pdf)
169
+ result(.success(editorResult))
170
+ } catch {
171
+ result(.failure(error))
172
+ }
173
+ }
174
+ } onDismiss: { cancelled in
175
+ if cancelled {
176
+ result(.success(nil))
177
+ dismiss()
178
+ } else {
179
+ result(.failure(exportFailedMessage))
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+ /// A modal design editor handling native errors.
186
+ private struct ModalDesignEditor: View {
187
+ @Environment(\.dismiss) private var dismiss
188
+ private let settings: EditorSettings
189
+ private let result: EditorBuilderResult
190
+
191
+ init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
192
+ self.settings = settings
193
+ self.result = result
194
+ }
195
+
196
+ var body: some View {
197
+ ModalEditor {
198
+ DesignEditor(engineSettings(for: settings))
199
+ .imgly.onCreate { engine in
200
+ try await OnCreate.load(settings, defaultSource: DesignEditor.defaultScene)(engine)
201
+ }
202
+ .imgly.onExport { engine, _ in
203
+ do {
204
+ let editorResult = try await OnExport.export(engine, .pdf)
205
+ result(.success(editorResult))
206
+ } catch {
207
+ result(.failure(error))
208
+ }
209
+ }
210
+ } onDismiss: { cancelled in
211
+ if cancelled {
212
+ result(.success(nil))
213
+ dismiss()
214
+ } else {
215
+ result(.failure(exportFailedMessage))
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ /// A modal photo editor handling native errors.
222
+ private struct ModalPhotoEditor: View {
223
+ @Environment(\.dismiss) private var dismiss
224
+ private let settings: EditorSettings
225
+ private let result: EditorBuilderResult
226
+
227
+ init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
228
+ self.settings = settings
229
+ self.result = result
230
+ }
231
+
232
+ var body: some View {
233
+ ModalEditor {
234
+ PhotoEditor(engineSettings(for: settings))
235
+ .imgly.onCreate { engine in
236
+ try await OnCreate
237
+ .load(settings, settings.source?.type ?? .image, defaultSource: PhotoEditor.defaultImage)(engine)
238
+ }
239
+ .imgly.onExport { engine, _ in
240
+ do {
241
+ let editorResult = try await OnExport.export(engine, .png)
242
+ result(.success(editorResult))
243
+ } catch {
244
+ result(.failure(error))
245
+ }
246
+ }
247
+ } onDismiss: { cancelled in
248
+ if cancelled {
249
+ result(.success(nil))
250
+ dismiss()
251
+ } else {
252
+ result(.failure(exportFailedMessage))
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ /// A modal video editor handling native errors.
259
+ private struct ModalVideoEditor: View {
260
+ @Environment(\.dismiss) private var dismiss
261
+ private let settings: EditorSettings
262
+ private let result: EditorBuilderResult
263
+
264
+ init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
265
+ self.settings = settings
266
+ self.result = result
267
+ }
268
+
269
+ var body: some View {
270
+ ModalEditor {
271
+ VideoEditor(engineSettings(for: settings))
272
+ .imgly.onCreate { engine in
273
+ try await OnCreate.load(settings, defaultSource: VideoEditor.defaultScene)(engine)
274
+ }
275
+ .imgly.onExport { engine, eventHandler in
276
+ do {
277
+ let editorResult = try await OnExport.exportVideo(engine, eventHandler, .mp4)
278
+ result(.success(editorResult))
279
+ } catch {
280
+ result(.failure(error))
281
+ }
282
+ }
283
+ } onDismiss: { cancelled in
284
+ if cancelled {
285
+ result(.success(nil))
286
+ dismiss()
287
+ } else {
288
+ result(.failure(exportFailedMessage))
289
+ }
290
+ }
291
+ }
292
+ }
293
+ }
@@ -0,0 +1,52 @@
1
+ /// An enum containing all prebuild editor configurations.
2
+ @objc public enum EditorPreset: Int {
3
+ /// The apparel editor.
4
+ case apparel
5
+
6
+ /// The postcard editor.
7
+ case postcard
8
+
9
+ /// The photo editor.
10
+ case photo
11
+
12
+ /// The video editor.
13
+ case video
14
+
15
+ /// The design editor.
16
+ case design
17
+
18
+ // Converts enum case to the corresponding string
19
+ public var stringValue: String {
20
+ switch self {
21
+ case .apparel: "apparel"
22
+ case .postcard: "postcard"
23
+ case .photo: "photo"
24
+ case .video: "video"
25
+ case .design: "design"
26
+ }
27
+ }
28
+
29
+ // Initialize from string
30
+ public static func fromString(_ rawValue: String) -> EditorPreset {
31
+ switch rawValue {
32
+ case "apparel": .apparel
33
+ case "postcard": .postcard
34
+ case "photo": .photo
35
+ case "video": .video
36
+ case "design": .design
37
+ default: .design
38
+ }
39
+ }
40
+ }
41
+
42
+ @objc @objcMembers public class EditorPresetParser: NSObject {
43
+ // Method to convert from NSString to EditorPreset enum
44
+ public static func fromString(_ rawValue: NSString) -> EditorPreset {
45
+ EditorPreset.fromString(rawValue as String)
46
+ }
47
+
48
+ // Method to convert from EditorPreset enum to NSString
49
+ public static func toString(_ preset: EditorPreset) -> NSString {
50
+ preset.stringValue as NSString
51
+ }
52
+ }
@@ -0,0 +1,27 @@
1
+ /// A struct representing the result of an editor export.
2
+ @objc @objcMembers public class EditorResult: NSObject {
3
+ /// The source of the exported scene.
4
+ public let scene: String?
5
+
6
+ /// The source of the exported artifact, e.g. image, video.
7
+ public let artifact: String?
8
+
9
+ /// The source of the exported thumbnail.
10
+ public let thumbnail: String?
11
+
12
+ /// The associated metadata.
13
+ public let metadata: [String: Any]
14
+
15
+ /// Creates a new `EditorResult`.
16
+ /// - Parameters:
17
+ /// - scene: The source of the exported scene.
18
+ /// - artifact: The source of the exported artifact, e.g. image, video.
19
+ /// - thumbnail: The source of the exported thumbnail.
20
+ /// - metadata: The associated metadata.
21
+ public init(scene: String?, artifact: String?, thumbnail: String?, metadata: [String: Any] = [:]) {
22
+ self.scene = scene
23
+ self.artifact = artifact
24
+ self.thumbnail = thumbnail
25
+ self.metadata = metadata
26
+ }
27
+ }
@@ -0,0 +1,33 @@
1
+ /// A struct containing all necessary settings to setup the editor.
2
+ @objc @objcMembers public class EditorSettings: NSObject, Codable {
3
+ /// The license key.
4
+ public let license: String
5
+
6
+ /// The base uri for the assets included in the scene that have a relative source.
7
+ public let sceneBaseUri: String
8
+
9
+ /// The base uri of the default assets in the asset library.
10
+ public let assetBaseUri: String?
11
+
12
+ /// The id of the current user.
13
+ public let userId: String?
14
+
15
+ /// The source to load into the editor.
16
+ public var source: Source?
17
+
18
+ /// Creates a new instance from a given dictionary.
19
+ ///
20
+ /// - Parameters:
21
+ /// - dictionary: The dictionary to convert the instance from.
22
+ /// - Returns: The `EditorSettings` instance.
23
+ public static func fromDictionary(_ dictionary: [String: Any]) -> EditorSettings? {
24
+ do {
25
+ let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
26
+ let settings = try JSONDecoder().decode(EditorSettings.self, from: data)
27
+ return settings
28
+ } catch {
29
+ print("Error decoding dictionary: \(error)")
30
+ return nil
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,11 @@
1
+ /// The `EditorSourceType` defines the type of source that is loaded into the editor.
2
+ public enum EditorSourceType: String, Codable {
3
+ /// A `.scene` file.
4
+ case scene
5
+
6
+ /// An image file, e.g. `.png`.
7
+ case image
8
+
9
+ /// A video file, e.g. `.mp4`.
10
+ case video
11
+ }
@@ -0,0 +1,8 @@
1
+ /// A struct to declare a suitable source for the editor.
2
+ public struct Source: Codable {
3
+ /// The source to load into the editor.
4
+ public var source: String
5
+
6
+ /// The source type.
7
+ public var type: EditorSourceType
8
+ }
@@ -0,0 +1,55 @@
1
+ import IMGLYEditor
2
+ import SwiftUI
3
+
4
+ /// The `ModalEditor` contains an editor and adds the top navigation bar.
5
+ public struct ModalEditor<Editor: View, Label: View>: View {
6
+ @ViewBuilder private let editor: () -> Editor
7
+ @ViewBuilder private let dismissLabel: () -> Label
8
+ private let onDismiss: (_ cancelled: Bool) -> Void
9
+
10
+ /// Initializes a new `ModalEditor`.
11
+ /// - Parameters:
12
+ /// - editor: The editor that is contained.
13
+ /// - dismissLabel: The label used for the dismiss action.
14
+ /// - onDismiss: The closure called when the editor is dismissed.
15
+ /// - cancelled: Indicates whether the editor has been dismissed by the user.
16
+ /// If `false`, the editor has been closed due to an error.
17
+ public init(@ViewBuilder editor: @escaping () -> Editor,
18
+ @ViewBuilder dismissLabel: @escaping () -> Label = { SwiftUI.Label("Home", systemImage: "house") },
19
+ onDismiss: @escaping (_ cancelled: Bool) -> Void) {
20
+ self.editor = editor
21
+ self.dismissLabel = dismissLabel
22
+ self.onDismiss = onDismiss
23
+ }
24
+
25
+ @State private var isBackButtonHidden = false
26
+ @Environment(\.dismiss) private var dismiss
27
+
28
+ @ViewBuilder private var dismissButton: some View {
29
+ Button {
30
+ onDismiss(true)
31
+ } label: {
32
+ dismissLabel()
33
+ }
34
+ }
35
+
36
+ public var body: some View {
37
+ NavigationView {
38
+ editor()
39
+ .onPreferenceChange(BackButtonHiddenKey.self) { newValue in
40
+ isBackButtonHidden = newValue
41
+ }
42
+ .toolbar {
43
+ ToolbarItem(placement: .navigationBarLeading) {
44
+ if !isBackButtonHidden {
45
+ dismissButton
46
+ }
47
+ }
48
+ }
49
+ .onDisappear(perform: {
50
+ onDismiss(false)
51
+ })
52
+ }
53
+ .navigationViewStyle(.stack)
54
+ }
55
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@imgly/editor-react-native",
3
+ "version": "1.40.0",
4
+ "description": "CreativeEditor SDK for React Native - enable photo, video and design editing for your users on iOS and Android.",
5
+ "react-native": "index.js",
6
+ "source": "index.js",
7
+ "types": "index.d.ts",
8
+ "files": [
9
+ "src",
10
+ "index.js",
11
+ "index.d.ts",
12
+ "android",
13
+ "ios",
14
+ "IMGLYEditorModule.podspec",
15
+ "README.md",
16
+ "LICENSE.md",
17
+ "!android/build",
18
+ "!ios/build",
19
+ "!**/__tests__",
20
+ "!**/__fixtures__",
21
+ "!**/__mocks__"
22
+ ],
23
+ "keywords": [
24
+ "react-native",
25
+ "ios",
26
+ "android",
27
+ "cesdk",
28
+ "editor",
29
+ "imgly"
30
+ ],
31
+ "author": "IMG.LY GmbH",
32
+ "license": "SEE LICENSE IN LICENSE.md",
33
+ "homepage": "https://img.ly",
34
+ "peerDependencies": {
35
+ "react": "*",
36
+ "react-native": "*"
37
+ },
38
+ "codegenConfig": {
39
+ "name": "IMGLYEditorModuleSpec",
40
+ "type": "modules",
41
+ "jsSrcsDir": "./",
42
+ "android": {
43
+ "javaPackageName": "ly.img.editor.reactnative.module"
44
+ }
45
+ }
46
+ }