@imgly/editor-react-native 1.72.3 → 1.73.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.
Files changed (126) hide show
  1. package/IMGLYEditorModule.podspec +23 -0
  2. package/android/build.gradle +9 -6
  3. package/android/src/main/AndroidManifest.xml +1 -1
  4. package/android/src/main/assets/scene/apparel.scene +1 -0
  5. package/android/src/main/assets/scene/design.scene +1 -0
  6. package/android/src/main/assets/scene/postcard.scene +1 -0
  7. package/android/src/main/assets/scene/video.scene +1 -0
  8. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/ApparelConfigurationBuilder.kt +113 -0
  9. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/EditorActivity.kt +37 -0
  10. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnCreate.kt +190 -0
  11. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnExport.kt +82 -0
  12. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnLoaded.kt +88 -0
  13. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/CanvasMenu.kt +45 -0
  14. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Dock.kt +37 -0
  15. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/InspectorBar.kt +52 -0
  16. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/NavigationBar.kt +45 -0
  17. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Overlay.kt +15 -0
  18. package/android/src/main/kotlin/ly/img/editor/configuration/design/DesignConfigurationBuilder.kt +106 -0
  19. package/android/src/main/kotlin/ly/img/editor/configuration/design/EditorActivity.kt +37 -0
  20. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnCreate.kt +162 -0
  21. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnExport.kt +82 -0
  22. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnLoaded.kt +10 -0
  23. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/CanvasMenu.kt +45 -0
  24. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Dock.kt +35 -0
  25. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/InspectorBar.kt +52 -0
  26. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/NavigationBar.kt +45 -0
  27. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Overlay.kt +15 -0
  28. package/android/src/main/kotlin/ly/img/editor/configuration/photo/EditorActivity.kt +37 -0
  29. package/android/src/main/kotlin/ly/img/editor/configuration/photo/PhotoConfigurationBuilder.kt +106 -0
  30. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnCreate.kt +143 -0
  31. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnExport.kt +82 -0
  32. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnLoaded.kt +49 -0
  33. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/CanvasMenu.kt +45 -0
  34. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Dock.kt +43 -0
  35. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/InspectorBar.kt +52 -0
  36. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/NavigationBar.kt +45 -0
  37. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Overlay.kt +15 -0
  38. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/EditorActivity.kt +37 -0
  39. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/PostcardConfigurationBuilder.kt +106 -0
  40. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnCreate.kt +149 -0
  41. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnExport.kt +82 -0
  42. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnLoaded.kt +58 -0
  43. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/CanvasMenu.kt +45 -0
  44. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Dock.kt +243 -0
  45. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/InspectorBar.kt +52 -0
  46. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/NavigationBar.kt +76 -0
  47. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Overlay.kt +15 -0
  48. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/ext/Engine.kt +107 -0
  49. package/android/src/main/kotlin/ly/img/editor/configuration/video/EditorActivity.kt +37 -0
  50. package/android/src/main/kotlin/ly/img/editor/configuration/video/VideoConfigurationBuilder.kt +135 -0
  51. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnCreate.kt +191 -0
  52. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnExport.kt +98 -0
  53. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnLoaded.kt +20 -0
  54. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/BottomPanel.kt +13 -0
  55. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/CanvasMenu.kt +45 -0
  56. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Dock.kt +71 -0
  57. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/InspectorBar.kt +68 -0
  58. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/NavigationBar.kt +57 -0
  59. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Overlay.kt +421 -0
  60. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/CheckCircleOutline.kt +79 -0
  61. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/ErrorOutline.kt +92 -0
  62. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/IconPack.kt +14 -0
  63. package/android/src/main/kotlin/ly/img/editor/configuration/video/model/ExportStatus.kt +39 -0
  64. package/android/src/main/kotlin/ly/img/editor/reactnative/module/activity/EditorActivity.kt +2 -0
  65. package/android/src/main/kotlin/ly/img/editor/reactnative/module/builder/EditorBuilder.kt +240 -282
  66. package/ios/Extensions/OnCreate+.swift +38 -62
  67. package/ios/IMGLYEditorModule.swift +10 -1
  68. package/ios/Model/EditorBuilder.swift +132 -225
  69. package/ios/Model/ModalEditorConfiguration.swift +40 -0
  70. package/ios/Model/Source.swift +8 -0
  71. package/ios/StarterKits/Apparel/ApparelEditorConfiguration.swift +46 -0
  72. package/ios/StarterKits/Apparel/ApparelEditorStarterKit.swift +30 -0
  73. package/ios/StarterKits/Apparel/callbacks/OnChanged+Apparel.swift +116 -0
  74. package/ios/StarterKits/Apparel/callbacks/OnCreate+Apparel.swift +197 -0
  75. package/ios/StarterKits/Apparel/callbacks/OnExport+Apparel.swift +29 -0
  76. package/ios/StarterKits/Apparel/components/CanvasMenu+Apparel.swift +22 -0
  77. package/ios/StarterKits/Apparel/components/Dock+Apparel.swift +19 -0
  78. package/ios/StarterKits/Apparel/components/InspectorBar+Apparel.swift +35 -0
  79. package/ios/StarterKits/Apparel/components/NavigationBar+Apparel.swift +26 -0
  80. package/ios/StarterKits/Design/DesignEditorConfiguration.swift +43 -0
  81. package/ios/StarterKits/Design/DesignEditorStarterKit.swift +30 -0
  82. package/ios/StarterKits/Design/callbacks/OnCreate+Design.swift +131 -0
  83. package/ios/StarterKits/Design/callbacks/OnExport+Design.swift +30 -0
  84. package/ios/StarterKits/Design/components/CanvasMenu+Design.swift +22 -0
  85. package/ios/StarterKits/Design/components/Dock+Design.swift +23 -0
  86. package/ios/StarterKits/Design/components/InspectorBar+Design.swift +35 -0
  87. package/ios/StarterKits/Design/components/NavigationBar+Design.swift +24 -0
  88. package/ios/StarterKits/Photo/PhotoEditorConfiguration.swift +48 -0
  89. package/ios/StarterKits/Photo/PhotoEditorStarterKit.swift +30 -0
  90. package/ios/StarterKits/Photo/callbacks/OnChanged+Photo.swift +25 -0
  91. package/ios/StarterKits/Photo/callbacks/OnCreate+Photo.swift +138 -0
  92. package/ios/StarterKits/Photo/callbacks/OnExport+Photo.swift +29 -0
  93. package/ios/StarterKits/Photo/callbacks/OnLoaded+Photo.swift +18 -0
  94. package/ios/StarterKits/Photo/components/CanvasMenu+Photo.swift +22 -0
  95. package/ios/StarterKits/Photo/components/Dock+Photo.swift +23 -0
  96. package/ios/StarterKits/Photo/components/InspectorBar+Photo.swift +39 -0
  97. package/ios/StarterKits/Photo/components/NavigationBar+Photo.swift +24 -0
  98. package/ios/StarterKits/Photo/examples/ExampleForceCrop.swift +30 -0
  99. package/ios/StarterKits/Postcard/PostcardEditorConfiguration.swift +45 -0
  100. package/ios/StarterKits/Postcard/PostcardEditorStarterKit.swift +30 -0
  101. package/ios/StarterKits/Postcard/callbacks/OnChanged+Postcard.swift +92 -0
  102. package/ios/StarterKits/Postcard/callbacks/OnCreate+Postcard.swift +127 -0
  103. package/ios/StarterKits/Postcard/callbacks/OnExport+Postcard.swift +29 -0
  104. package/ios/StarterKits/Postcard/components/CanvasMenu+Postcard.swift +22 -0
  105. package/ios/StarterKits/Postcard/components/Dock+Postcard.swift +34 -0
  106. package/ios/StarterKits/Postcard/components/DockButtons+Postcard.swift +129 -0
  107. package/ios/StarterKits/Postcard/components/InspectorBar+Postcard.swift +35 -0
  108. package/ios/StarterKits/Postcard/components/NavigationBar+Postcard.swift +38 -0
  109. package/ios/StarterKits/Video/VideoEditorConfiguration.swift +54 -0
  110. package/ios/StarterKits/Video/VideoEditorStarterKit.swift +30 -0
  111. package/ios/StarterKits/Video/callbacks/OnCreate+Video.swift +137 -0
  112. package/ios/StarterKits/Video/callbacks/OnExport+Video.swift +46 -0
  113. package/ios/StarterKits/Video/components/BottomPanel+Video.swift +16 -0
  114. package/ios/StarterKits/Video/components/CanvasMenu+Video.swift +22 -0
  115. package/ios/StarterKits/Video/components/Dock+Video.swift +30 -0
  116. package/ios/StarterKits/Video/components/InspectorBar+Video.swift +43 -0
  117. package/ios/StarterKits/Video/components/NavigationBar+Video.swift +32 -0
  118. package/ios/StarterKits/Video/examples/ExampleVideoDurationConstraints.swift +23 -0
  119. package/ios/StarterKits/apparel-ui-b-empty.scene +1 -0
  120. package/ios/StarterKits/design-ui-empty.scene +1 -0
  121. package/ios/StarterKits/photo-ui-empty.png +0 -0
  122. package/ios/StarterKits/postcard-empty.scene +1 -0
  123. package/ios/StarterKits/video-empty.scene +1 -0
  124. package/package.json +1 -1
  125. package/src/NativeIMGLYEditor.ts +1 -1
  126. package/ios/View/ModalEditor.swift +0 -43
@@ -0,0 +1,92 @@
1
+ import IMGLYEditor
2
+ import IMGLYEngine
3
+
4
+ // MARK: - Default OnChanged
5
+
6
+ extension PostcardEditorConfiguration {
7
+ /// The default `onChanged` handler.
8
+ static var defaultOnChangedHandler: OnChanged.Handler {
9
+ { update, context, _ in
10
+ switch update {
11
+ case let .page(_, newValue):
12
+ // Deselect all blocks.
13
+ try context.engine.block.findAllSelected().forEach {
14
+ try context.engine.block.setSelected($0, selected: false)
15
+ }
16
+
17
+ // Reset history.
18
+ let oldHistory = context.engine.editor.getActiveHistory()
19
+ let newHistory = context.engine.editor.createHistory()
20
+ context.engine.editor.setActiveHistory(newHistory)
21
+ context.engine.editor.destroyHistory(oldHistory)
22
+ try context.engine.editor.addUndoStep()
23
+
24
+ if let stack = try? context.engine.block.find(byType: .stack).first {
25
+ try context.engine.block.setEnum(stack, property: "stack/axis", value: "Depth")
26
+ }
27
+
28
+ let pages = try context.engine.scene.getPages()
29
+ for (i, block) in pages.enumerated() {
30
+ let isVisibilityEnabled = try context.engine.block.isScopeEnabled(block, key: "layer/visibility")
31
+ try context.engine.block.setScopeEnabled(block, key: "layer/visibility", enabled: true)
32
+ try context.engine.block.setVisible(block, visible: i == newValue)
33
+ try context.engine.block.setScopeEnabled(block, key: "layer/visibility", enabled: isVisibilityEnabled)
34
+ }
35
+
36
+ case let .viewMode(_, state):
37
+ if state.editorViewMode == .preview {
38
+ guard let scene = try context.engine.block.find(byType: .scene).first else {
39
+ throw EditorError("No scene found.")
40
+ }
41
+
42
+ // Disable camera clamping.
43
+ if try context.engine.scene.unstable_isCameraZoomClampingEnabled(scene) {
44
+ try context.engine.scene.unstable_disableCameraZoomClamping()
45
+ }
46
+ if try context.engine.scene.unstable_isCameraPositionClampingEnabled(scene) {
47
+ try context.engine.scene.unstable_disableCameraPositionClamping()
48
+ }
49
+
50
+ // Deselect all blocks.
51
+ try context.engine.block.findAllSelected().forEach {
52
+ try context.engine.block.setSelected($0, selected: false)
53
+ }
54
+
55
+ if let stack = try? context.engine.block.find(byType: .stack).first {
56
+ let layoutAxis = state.verticalSizeClass == .compact ? "Horizontal" : "Vertical"
57
+ try context.engine.block.setEnum(stack, property: "stack/axis", value: layoutAxis)
58
+ try context.engine.block.setInt(stack, property: "stack/spacing", value: 16)
59
+ }
60
+
61
+ let pages = try context.engine.scene.getPages()
62
+ for block in pages {
63
+ let isVisibilityEnabled = try context.engine.block.isScopeEnabled(block, key: "layer/visibility")
64
+ try context.engine.block.setScopeEnabled(block, key: "layer/visibility", enabled: true)
65
+ try context.engine.block.setVisible(block, visible: true)
66
+ try context.engine.block.setScopeEnabled(block, key: "layer/visibility", enabled: isVisibilityEnabled)
67
+ }
68
+
69
+ Task {
70
+ // Zoom to the entire scene.
71
+ try await context.engine.scene.zoom(
72
+ to: scene,
73
+ paddingLeft: Float(state.insets?.leading ?? 0),
74
+ paddingTop: Float(state.insets?.top ?? 0),
75
+ paddingRight: Float(state.insets?.trailing ?? 0),
76
+ paddingBottom: Float(state.insets?.bottom ?? 0),
77
+ )
78
+
79
+ // Deselect all blocks.
80
+ let selectedBlocks = context.engine.block.findAllSelected()
81
+ try selectedBlocks.forEach { try context.engine.block.setSelected($0, selected: false) }
82
+ }
83
+ } else {
84
+ try OnChanged.default(update, context)
85
+ }
86
+
87
+ default:
88
+ try OnChanged.default(update, context)
89
+ }
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,127 @@
1
+ import Foundation
2
+ import IMGLYEditor
3
+ import IMGLYEngine
4
+
5
+ // MARK: - Default OnCreate
6
+
7
+ public extension PostcardEditorConfiguration {
8
+ /// The default `onCreate` handler.
9
+ internal static var defaultOnCreateHandler: OnCreate.Handler {
10
+ { engine, _ in
11
+ try await defaultOnCreate()(engine)
12
+ }
13
+ }
14
+
15
+ /// Default postcard editor specific `OnCreate.Callback` implementation with solution specific settings, scene
16
+ /// and editor creation setup.
17
+ /// - Parameters:
18
+ /// - preCreateScene: Callback to do any pre scene loading tasks such as applying settings.
19
+ /// Defaults to `PostcardEditorConfiguration.defaultPreCreateScene`.
20
+ /// - createScene: Callback to load/create the scene and load asset sources. Defaults to
21
+ /// `PostcardEditorConfiguration.defaultCreateScene`.
22
+ /// - loadAssetSources: Callback to load any asset sources. Defaults to
23
+ /// `PostcardEditorConfiguration.defaultLoadAssetSources`.
24
+ /// - postCreateScene: Callback to do any post scene loading tasks. Defaults to
25
+ /// `PostcardEditorConfiguration.defaultPostCreateScene`.
26
+ /// - Returns: A composed `OnCreate.Callback`that sequentially executes all three initialization phases.
27
+ static func defaultOnCreate(
28
+ preCreateScene: @escaping OnCreate.Callback = defaultPreCreateScene,
29
+ createScene: @escaping OnCreate.Callback = defaultCreateScene,
30
+ loadAssetSources: @escaping OnCreate.Callback = defaultLoadAssetSources,
31
+ postCreateScene: @escaping OnCreate.Callback = defaultPostCreateScene,
32
+ ) -> OnCreate.Callback {
33
+ { engine in
34
+ try await preCreateScene(engine)
35
+ try await createScene(engine)
36
+ try await loadAssetSources(engine)
37
+ try await postCreateScene(engine)
38
+ }
39
+ }
40
+
41
+ /// Configures engine settings before scene loading.
42
+ ///
43
+ /// Sets editor role, touch gestures, camera clamping, and global scopes.
44
+ static let defaultPreCreateScene: OnCreate.Callback = { engine in
45
+ try engine.editor.setRole("Adopter")
46
+ try engine.editor.setSettingEnum("camera/clamping/overshootMode", value: "Center")
47
+
48
+ let highlightColor: IMGLYEngine.Color = try engine.editor.getSettingColor("highlightColor")
49
+ try engine.editor.setSettingColor("placeholderHighlightColor", color: highlightColor)
50
+
51
+ try engine.editor.setSettingBool("touch/dragStartCanSelect", value: false)
52
+ try engine.editor.setSettingEnum("touch/pinchAction", value: "Zoom")
53
+ try engine.editor.setSettingEnum("touch/rotateAction", value: "None")
54
+
55
+ try ([
56
+ "appearance/adjustments", "appearance/filter", "appearance/effect",
57
+ "appearance/blur", "appearance/shadow",
58
+ "editor/select",
59
+ "fill/change", "fill/changeType",
60
+ "layer/crop", "layer/move", "layer/resize", "layer/rotate", "layer/flip",
61
+ "layer/opacity", "layer/blendMode", "layer/visibility", "layer/clipping",
62
+ "lifecycle/destroy", "lifecycle/duplicate",
63
+ "stroke/change", "shape/change",
64
+ "text/edit", "text/character",
65
+ ]).forEach { scope in
66
+ try engine.editor.setGlobalScope(key: scope, value: .defer)
67
+ }
68
+ }
69
+
70
+ /// Loads the built-in empty postcard scene.
71
+ static let defaultCreateScene: OnCreate.Callback = { engine in
72
+ // highlight-starter-kit-on-create-scene
73
+ let sceneURL = Bundle(for: PostcardEditorConfiguration.self).url(
74
+ forResource: "postcard-empty",
75
+ withExtension: "scene",
76
+ )!
77
+ try await engine.scene.load(from: sceneURL)
78
+ // highlight-starter-kit-on-create-scene
79
+ }
80
+
81
+ /// Registers all default and demo asset sources, plus text and photo roll sources.
82
+ static let defaultLoadAssetSources: OnCreate.Callback = { engine in
83
+ // highlight-starter-kit-on-load-asset-sources
84
+ let assetSources: [String: URL] = [
85
+ Engine.DefaultAssetSource.sticker.rawValue: Engine.assetBaseURL,
86
+ Engine.DefaultAssetSource.vectorPath.rawValue: Engine.assetBaseURL,
87
+ Engine.DefaultAssetSource.filterLut.rawValue: Engine.assetBaseURL,
88
+ Engine.DefaultAssetSource.filterDuotone.rawValue: Engine.assetBaseURL,
89
+ Engine.DefaultAssetSource.colorsDefaultPalette.rawValue: Engine.assetBaseURL,
90
+ Engine.DefaultAssetSource.effect.rawValue: Engine.assetBaseURL,
91
+ Engine.DefaultAssetSource.blur.rawValue: Engine.assetBaseURL,
92
+ Engine.DefaultAssetSource.typeface.rawValue: Engine.assetBaseURL,
93
+ Engine.DefaultAssetSource.cropPresets.rawValue: Engine.assetBaseURL,
94
+ Engine.DefaultAssetSource.pagePresets.rawValue: Engine.assetBaseURL,
95
+
96
+ Engine.DemoAssetSource.image.rawValue: Engine.assetBaseURL,
97
+ Engine.DemoAssetSource.textComponents.rawValue: Engine.assetBaseURL,
98
+ ]
99
+
100
+ try await withThrowingTaskGroup(of: Void.self) { group in
101
+ for assetSource in assetSources {
102
+ group.addTask {
103
+ try await engine.populateAssetSource(id: assetSource.key, baseURL: assetSource.value)
104
+ }
105
+ }
106
+ try await group.waitForAll()
107
+ }
108
+
109
+ try engine.asset.addLocalSource(
110
+ sourceID: Engine.DemoAssetSource.imageUpload.rawValue,
111
+ supportedMimeTypes: Engine.DemoAssetSource.imageUpload.mimeTypes,
112
+ )
113
+
114
+ try await engine.asset.addSource(TextAssetSource(engine: engine))
115
+ try engine.asset.addSource(PhotoRollAssetSource(engine: engine))
116
+ // highlight-starter-kit-on-load-asset-sources
117
+ }
118
+
119
+ /// Configures postcard-specific layout and permission behavior.
120
+ static let defaultPostCreateScene: OnCreate.Callback = { engine in
121
+ if let stack = try engine.block.find(byType: .stack).first {
122
+ try engine.block.setEnum(stack, property: "stack/axis", value: "Horizontal")
123
+ }
124
+
125
+ try engine.editor.setGlobalScope(key: "editor/add", value: .defer)
126
+ }
127
+ }
@@ -0,0 +1,29 @@
1
+ import IMGLYEditor
2
+ import IMGLYEngine
3
+ import UniformTypeIdentifiers
4
+
5
+ // MARK: - Default OnExport
6
+
7
+ extension PostcardEditorConfiguration {
8
+ /// The default export handler.
9
+ ///
10
+ /// Exports the scene as PDF and opens the system share sheet.
11
+ static var defaultOnExportHandler: OnExport.Handler {
12
+ { engine, eventHandler, _ in
13
+ // highlight-starter-kit-on-export
14
+ guard let scene = try engine.scene.get() else {
15
+ throw EditorError("No scene was found.")
16
+ }
17
+ let data = try await engine.block.export(scene, mimeType: .pdf) { engine in
18
+ try engine.scene.getPages().forEach {
19
+ try engine.block.setScopeEnabled($0, key: "layer/visibility", enabled: true)
20
+ try engine.block.setVisible($0, visible: true)
21
+ }
22
+ }
23
+ let url = FileManager.default.temporaryDirectory.appendingPathComponent("Export", conformingTo: .pdf)
24
+ try data.write(to: url, options: [.atomic])
25
+ eventHandler.send(.shareFile(url))
26
+ // highlight-starter-kit-on-export
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,22 @@
1
+ import IMGLYEditor
2
+
3
+ // MARK: - Canvas Menu
4
+
5
+ extension PostcardEditorConfiguration {
6
+ /// The default canvas menu configuration.
7
+ static var defaultCanvasMenu: CanvasMenu.Configuration {
8
+ CanvasMenu.Configuration { builder in
9
+ // highlight-starter-kit-canvas-menu
10
+ builder.items { _ in
11
+ CanvasMenu.Buttons.selectGroup()
12
+ CanvasMenu.Divider()
13
+ CanvasMenu.Buttons.bringForward()
14
+ CanvasMenu.Buttons.sendBackward()
15
+ CanvasMenu.Divider()
16
+ CanvasMenu.Buttons.duplicate()
17
+ CanvasMenu.Buttons.delete()
18
+ }
19
+ // highlight-starter-kit-canvas-menu
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,34 @@
1
+ import IMGLYEditor
2
+ import SwiftUI
3
+
4
+ // MARK: - Dock
5
+
6
+ extension PostcardEditorConfiguration {
7
+ /// The default dock configuration.
8
+ static var defaultDock: Dock.Configuration {
9
+ Dock.Configuration { builder in
10
+ // highlight-starter-kit-dock
11
+ builder.items { _ in
12
+ Dock.Buttons
13
+ .assetLibrary(
14
+ isVisible: { try $0.engine.scene.getPages().first == $0.engine.scene.getCurrentPage() },
15
+ modifier: { _ in Dock.Buttons.AssetLibraryModifier() },
16
+ )
17
+ Dock.Custom(id: "ly.img.component.dock.postcard.divider", content: { _ in
18
+ Divider()
19
+ .frame(height: 40)
20
+ .padding(.leading, 8)
21
+ }, isVisible: { try $0.engine.scene.getPages().first == $0.engine.scene.getCurrentPage() })
22
+ Dock.Buttons.designColors()
23
+ Dock.Buttons.greetingFont()
24
+ Dock.Buttons.greetingSize()
25
+ Dock.Buttons.greetingColors()
26
+ }
27
+ builder.alignment = {
28
+ try $0.engine.scene.getPages().first == $0.engine.scene.getCurrentPage() ? .leading : .center
29
+ }
30
+ builder.scrollDisabled = { _ in true }
31
+ // highlight-starter-kit-dock
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,129 @@
1
+ @_spi(Internal) import IMGLYEditor
2
+ import IMGLYEngine
3
+ import SwiftUI
4
+
5
+ // MARK: - Dock Button IDs
6
+
7
+ extension Dock.Buttons.ID {
8
+ /// The id of the ``Dock/Buttons/designColors(action:title:icon:isEnabled:isVisible:)`` button.
9
+ static var designColors: EditorComponentID { "ly.img.component.dock.button.postcard.designColors" }
10
+ /// The id of the ``Dock/Buttons/greetingColors(action:title:icon:isEnabled:isVisible:)`` button.
11
+ static var greetingColors: EditorComponentID { "ly.img.component.dock.button.postcard.namedColors" }
12
+ /// The id of the ``Dock/Buttons/greetingFont(action:title:icon:isEnabled:isVisible:)`` button.
13
+ static var greetingFont: EditorComponentID { "ly.img.component.dock.button.postcard.greetingFont" }
14
+ /// The id of the ``Dock/Buttons/greetingSize(action:title:icon:isEnabled:isVisible:)`` button.
15
+ static var greetingSize: EditorComponentID { "ly.img.component.dock.button.postcard.greetingSize" }
16
+ }
17
+
18
+ // MARK: - Dock Buttons
19
+
20
+ extension Dock.Buttons {
21
+ /// Creates a dock button that opens the selection colors sheet.
22
+ static func designColors(
23
+ action: @escaping Dock.Context.To<Void> = {
24
+ $0.eventHandler.send(.openSheet(type: .designColors()))
25
+ },
26
+ @ViewBuilder title: @escaping Dock.Context.To<some View> = { _ in
27
+ Text(.imgly.localized("ly_img_editor_dock_button_colors"))
28
+ },
29
+ @ViewBuilder icon: @escaping Dock.Context.To<some View> = { _ in SelectionColorsIcon() },
30
+ isEnabled: @escaping Dock.Context.To<Bool> = { _ in true },
31
+ isVisible: @escaping Dock.Context.To<Bool> = {
32
+ try $0.engine.scene.getPages().first == $0.engine.scene.getCurrentPage()
33
+ },
34
+ ) -> some Dock.Item {
35
+ Dock.Button(id: ID.designColors, action: action, label: { context in
36
+ let title = try title(context)
37
+ let icon = try icon(context)
38
+ Label { title } icon: { icon }
39
+ }, isEnabled: isEnabled, isVisible: isVisible)
40
+ }
41
+
42
+ /// Creates a dock button that opens the greeting color sheet.
43
+ static func greetingColors(
44
+ action: @escaping Dock.Context.To<Void> = {
45
+ guard let id = $0.engine.block.find(byName: "Greeting").first else { return }
46
+ $0.eventHandler.send(.openSheet(type: .greetingColors(id: id, colorPalette: [
47
+ .init("Governor Bay", .imgly.hex("#263BAA")!),
48
+ .init("Resolution Blue", .imgly.hex("#002094")!),
49
+ .init("Stratos", .imgly.hex("#001346")!),
50
+ .init("Blue Charcoal", .imgly.hex("#000514")!),
51
+ .init("Black", .imgly.hex("#000000")!),
52
+ .init("Dove Gray", .imgly.hex("#696969")!),
53
+ .init("Dusty Gray", .imgly.hex("#999999")!),
54
+ ])))
55
+ },
56
+ @ViewBuilder title: @escaping Dock.Context.To<some View> = { _ in
57
+ Text(.imgly.localized("ly_img_editor_dock_button_colors"))
58
+ },
59
+ @ViewBuilder icon: @escaping Dock.Context.To<some View> = {
60
+ let id = $0.engine.block.find(byName: "Greeting").first
61
+ return FillColorIcon()
62
+ .imgly.selection(id)
63
+ },
64
+ isEnabled: @escaping Dock.Context.To<Bool> = { _ in true },
65
+ isVisible: @escaping Dock.Context.To<Bool> = {
66
+ try $0.engine.scene.getPages().last == $0.engine.scene.getCurrentPage()
67
+ },
68
+ ) -> some Dock.Item {
69
+ Dock.Button(id: ID.greetingColors, action: action, label: { context in
70
+ let title = try title(context)
71
+ let icon = try icon(context)
72
+ Label { title } icon: { icon }
73
+ }, isEnabled: isEnabled, isVisible: isVisible)
74
+ }
75
+
76
+ /// Creates a dock button that opens the greeting font sheet.
77
+ static func greetingFont(
78
+ action: @escaping Dock.Context.To<Void> = {
79
+ guard let id = $0.engine.block.find(byName: "Greeting").first else { return }
80
+ $0.eventHandler.send(.openSheet(type: .greetingFont(id: id, fontFamilies: [
81
+ "Caveat", "Amatic SC", "Courier Prime", "Archivo", "Roboto", "Parisienne",
82
+ ])))
83
+ },
84
+ @ViewBuilder title: @escaping Dock.Context.To<some View> = { _ in
85
+ Text(.imgly.localized("ly_img_editor_dock_button_font"))
86
+ },
87
+ @ViewBuilder icon: @escaping Dock.Context.To<some View> = {
88
+ let id = $0.engine.block.find(byName: "Greeting").first
89
+ return FontIcon()
90
+ .imgly.selection(id)
91
+ },
92
+ isEnabled: @escaping Dock.Context.To<Bool> = { _ in true },
93
+ isVisible: @escaping Dock.Context.To<Bool> = {
94
+ try $0.engine.scene.getPages().last == $0.engine.scene.getCurrentPage()
95
+ },
96
+ ) -> some Dock.Item {
97
+ Dock.Button(id: ID.greetingFont, action: action, label: { context in
98
+ let title = try title(context)
99
+ let icon = try icon(context)
100
+ Label { title } icon: { icon }
101
+ }, isEnabled: isEnabled, isVisible: isVisible)
102
+ }
103
+
104
+ /// Creates a dock button that opens the greeting font size sheet.
105
+ static func greetingSize(
106
+ action: @escaping Dock.Context.To<Void> = {
107
+ guard let id = $0.engine.block.find(byName: "Greeting").first else { return }
108
+ $0.eventHandler.send(.openSheet(type: .greetingSize(id: id)))
109
+ },
110
+ @ViewBuilder title: @escaping Dock.Context.To<some View> = { _ in
111
+ Text(.imgly.localized("ly_img_editor_dock_button_size"))
112
+ },
113
+ @ViewBuilder icon: @escaping Dock.Context.To<some View> = { context in
114
+ let id = context.engine.block.find(byName: "Greeting").first
115
+ return FontSizeIcon()
116
+ .imgly.selection(id)
117
+ },
118
+ isEnabled: @escaping Dock.Context.To<Bool> = { _ in true },
119
+ isVisible: @escaping Dock.Context.To<Bool> = {
120
+ try $0.engine.scene.getPages().last == $0.engine.scene.getCurrentPage()
121
+ },
122
+ ) -> some Dock.Item {
123
+ Dock.Button(id: ID.greetingSize, action: action, label: { context in
124
+ let title = try title(context)
125
+ let icon = try icon(context)
126
+ Label { title } icon: { icon }
127
+ }, isEnabled: isEnabled, isVisible: isVisible)
128
+ }
129
+ }
@@ -0,0 +1,35 @@
1
+ import IMGLYEditor
2
+
3
+ // MARK: - Inspector Bar
4
+
5
+ extension PostcardEditorConfiguration {
6
+ /// The default inspector bar configuration.
7
+ static var defaultInspectorBar: InspectorBar.Configuration {
8
+ InspectorBar.Configuration { builder in
9
+ // highlight-starter-kit-inspector-bar
10
+ builder.items { _ in
11
+ InspectorBar.Buttons.replace()
12
+
13
+ InspectorBar.Buttons.editText()
14
+ InspectorBar.Buttons.formatText()
15
+ InspectorBar.Buttons.fillStroke()
16
+ InspectorBar.Buttons.textBackground()
17
+ InspectorBar.Buttons.crop()
18
+
19
+ InspectorBar.Buttons.adjustments()
20
+ InspectorBar.Buttons.filter()
21
+ InspectorBar.Buttons.effect()
22
+ InspectorBar.Buttons.blur()
23
+ InspectorBar.Buttons.shape()
24
+
25
+ InspectorBar.Buttons.selectGroup()
26
+ InspectorBar.Buttons.enterGroup()
27
+
28
+ InspectorBar.Buttons.layer()
29
+ InspectorBar.Buttons.duplicate()
30
+ InspectorBar.Buttons.delete()
31
+ }
32
+ // highlight-starter-kit-inspector-bar
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,38 @@
1
+ import IMGLYEditor
2
+
3
+ // MARK: - Navigation Bar
4
+
5
+ extension PostcardEditorConfiguration {
6
+ /// The default navigation bar configuration.
7
+ static var defaultNavigationBar: NavigationBar.Configuration {
8
+ NavigationBar.Configuration { builder in
9
+ // highlight-starter-kit-navigation-bar
10
+ builder.items { _ in
11
+ NavigationBar.ItemGroup(placement: .topBarLeading) {
12
+ NavigationBar.Buttons.closeEditor()
13
+ NavigationBar.Buttons.previousPage(
14
+ label: { _ in NavigationLabel(
15
+ .imgly.localized("ly_img_editor_navigation_bar_button_design"),
16
+ direction: .backward,
17
+ ) },
18
+ )
19
+ }
20
+ NavigationBar.ItemGroup(placement: .principal) {
21
+ NavigationBar.Buttons.undo()
22
+ NavigationBar.Buttons.redo()
23
+ NavigationBar.Buttons.togglePreviewMode()
24
+ }
25
+ NavigationBar.ItemGroup(placement: .topBarTrailing) {
26
+ NavigationBar.Buttons.nextPage(
27
+ label: { _ in NavigationLabel(
28
+ .imgly.localized("ly_img_editor_navigation_bar_button_write"),
29
+ direction: .forward,
30
+ ) },
31
+ )
32
+ NavigationBar.Buttons.export()
33
+ }
34
+ }
35
+ // highlight-starter-kit-navigation-bar
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,54 @@
1
+ import IMGLYEditor
2
+ import IMGLYEngine
3
+ import SwiftUI
4
+
5
+ // CE.SDK Starter Kit: Video Editor
6
+ //
7
+ // This starter kit provides a complete, production-ready Video Editor configuration
8
+ // with all configuration code inline and fully documented. Copy this file into your
9
+ // project and customize it to match your needs.
10
+
11
+ // MARK: - Configuration
12
+
13
+ public final class VideoEditorConfiguration: EditorConfiguration {
14
+ // MARK: - EditorConfiguration — Settings
15
+
16
+ /// The zoom padding for the canvas.
17
+ override public var zoomPadding: CGFloat? { 1 }
18
+
19
+ /// The asset library configuration.
20
+ ///
21
+ /// Includes video and audio categories for the video editor.
22
+ override public var assetLibrary: AssetLibraryConfiguration? {
23
+ AssetLibraryConfiguration { builder in
24
+ builder.includeAVResources = true
25
+ }
26
+ }
27
+
28
+ // MARK: - EditorConfiguration — Callbacks
29
+
30
+ /// The `onCreate` handler.
31
+ override public var onCreate: OnCreate.Handler? { Self.defaultOnCreateHandler }
32
+
33
+ /// The export handler.
34
+ ///
35
+ /// Default: Exports the current page as MP4 and opens the system share sheet.
36
+ override public var onExport: OnExport.Handler? { Self.defaultOnExportHandler }
37
+
38
+ // MARK: - EditorConfiguration — UI Components
39
+
40
+ /// The navigation bar configuration.
41
+ override public var navigationBar: NavigationBar.Configuration? { Self.defaultNavigationBar }
42
+
43
+ /// The dock configuration.
44
+ override public var dock: Dock.Configuration? { Self.defaultDock }
45
+
46
+ /// The inspector bar configuration.
47
+ override public var inspectorBar: InspectorBar.Configuration? { Self.defaultInspectorBar }
48
+
49
+ /// The canvas menu configuration.
50
+ override public var canvasMenu: CanvasMenu.Configuration? { Self.defaultCanvasMenu }
51
+
52
+ /// The bottom panel configuration.
53
+ override public var bottomPanel: BottomPanel.Configuration? { Self.defaultBottomPanel }
54
+ }
@@ -0,0 +1,30 @@
1
+ import IMGLYEditor
2
+ import IMGLYEngine
3
+ import SwiftUI
4
+
5
+ // MARK: - Starter Kit View
6
+
7
+ struct VideoEditorStarterKit: View {
8
+ // Provide `EngineSettings` with your license and an optional userId.
9
+ let settings = EngineSettings(
10
+ license: secrets.licenseKey, // Use nil for evaluation mode with watermark
11
+ userID: "<your unique user id>",
12
+ )
13
+
14
+ // highlight-starter-kit-view
15
+ var body: some View {
16
+ // highlight-starter-kit-composable
17
+ Editor(settings)
18
+ .imgly.configuration {
19
+ VideoEditorConfiguration()
20
+ }
21
+ // highlight-starter-kit-composable
22
+ }
23
+ // highlight-starter-kit-view
24
+ }
25
+
26
+ // MARK: - Preview
27
+
28
+ #Preview {
29
+ VideoEditorStarterKit()
30
+ }