@@ -10,42 +10,35 @@ import {
10
10
Text ,
11
11
} from '@invoke-ai/ui-library' ;
12
12
import { useAppSelector } from 'app/store/storeHooks' ;
13
- import type { CropBox } from 'features/editImageModal/lib/editor' ;
14
- import { closeEditImageModal , type EditImageModalState } from 'features/editImageModal/store' ;
13
+ import type { AspectRatioID } from 'features/controlLayers/store/types' ;
14
+ import { ASPECT_RATIO_MAP , isAspectRatioID } from 'features/controlLayers/store/types' ;
15
+ import type { CropBox } from 'features/cropper/lib/editor' ;
16
+ import { cropImageModalApi , type CropImageModalState } from 'features/cropper/store' ;
15
17
import { selectAutoAddBoardId } from 'features/gallery/store/gallerySelectors' ;
16
- import React , { useCallback , useEffect , useRef , useState } from 'react' ;
18
+ import React , { memo , useCallback , useEffect , useRef , useState } from 'react' ;
17
19
import { useUploadImageMutation } from 'services/api/endpoints/images' ;
20
+ import { objectEntries } from 'tsafe' ;
18
21
19
22
type Props = {
20
- editor : EditImageModalState [ 'editor' ] ;
21
- onApplyCrop : EditImageModalState [ 'onApplyCrop' ] ;
22
- onReady : EditImageModalState [ 'onReady' ] ;
23
+ editor : CropImageModalState [ 'editor' ] ;
24
+ onApplyCrop : CropImageModalState [ 'onApplyCrop' ] ;
25
+ onReady : CropImageModalState [ 'onReady' ] ;
23
26
} ;
24
27
25
- const CROP_ASPECT_RATIO_MAP : Record < string , number > = {
26
- '16:9' : 16 / 9 ,
27
- '3:2' : 3 / 2 ,
28
- '4:3' : 4 / 3 ,
29
- '1:1' : 1 ,
30
- '3:4' : 3 / 4 ,
31
- '2:3' : 2 / 3 ,
32
- '9:16' : 9 / 16 ,
33
- } ;
34
-
35
- const getAspectRatioString = ( ratio : number | null ) => {
28
+ const getAspectRatioString = ( ratio : number | null ) : AspectRatioID => {
36
29
if ( ! ratio ) {
37
- return 'free ' ;
30
+ return 'Free ' ;
38
31
}
39
- const entries = Object . entries ( CROP_ASPECT_RATIO_MAP ) ;
32
+ const entries = objectEntries ( ASPECT_RATIO_MAP ) ;
40
33
for ( const [ key , value ] of entries ) {
41
- if ( value === ratio ) {
34
+ if ( value . ratio === ratio ) {
42
35
return key ;
43
36
}
44
37
}
45
- return 'free ' ;
38
+ return 'Free ' ;
46
39
} ;
47
40
48
- export const EditorContainer = ( { editor, onApplyCrop, onReady } : Props ) => {
41
+ export const CropImageEditor = memo ( ( { editor, onApplyCrop, onReady } : Props ) => {
49
42
const containerRef = useRef < HTMLDivElement > ( null ) ;
50
43
const [ zoom , setZoom ] = useState ( 100 ) ;
51
44
const [ cropBox , setCropBox ] = useState < CropBox | null > ( null ) ;
@@ -90,12 +83,15 @@ export const EditorContainer = ({ editor, onApplyCrop, onReady }: Props) => {
90
83
const handleAspectRatioChange = useCallback (
91
84
( e : React . ChangeEvent < HTMLSelectElement > ) => {
92
85
const newRatio = e . target . value ;
86
+ if ( ! isAspectRatioID ( newRatio ) ) {
87
+ return ;
88
+ }
93
89
setAspectRatio ( newRatio ) ;
94
90
95
- if ( newRatio === 'free ' ) {
91
+ if ( newRatio === 'Free ' ) {
96
92
editor . setCropAspectRatio ( null ) ;
97
93
} else {
98
- editor . setCropAspectRatio ( CROP_ASPECT_RATIO_MAP [ newRatio ] ?? null ) ;
94
+ editor . setCropAspectRatio ( ASPECT_RATIO_MAP [ newRatio ] ?. ratio ?? null ) ;
99
95
}
100
96
} ,
101
97
[ editor ]
@@ -107,11 +103,11 @@ export const EditorContainer = ({ editor, onApplyCrop, onReady }: Props) => {
107
103
108
104
const handleApplyCrop = useCallback ( async ( ) => {
109
105
await onApplyCrop ( ) ;
110
- closeEditImageModal ( ) ;
106
+ cropImageModalApi . close ( ) ;
111
107
} , [ onApplyCrop ] ) ;
112
108
113
109
const handleCancelCrop = useCallback ( ( ) => {
114
- closeEditImageModal ( ) ;
110
+ cropImageModalApi . close ( ) ;
115
111
} , [ ] ) ;
116
112
117
113
const handleExport = useCallback ( async ( ) => {
@@ -157,15 +153,15 @@ export const EditorContainer = ({ editor, onApplyCrop, onReady }: Props) => {
157
153
< Flex gap = { 2 } alignItems = "center" >
158
154
< FormControl flex = { 1 } >
159
155
< FormLabel > Aspect Ratio:</ FormLabel >
160
- < Select size = "sm" value = { aspectRatio } onChange = { handleAspectRatioChange } w = { 64 } >
161
- < option value = "free " > Free</ option >
156
+ < Select size = "sm" value = { aspectRatio } onChange = { handleAspectRatioChange } w = { 32 } >
157
+ < option value = "Free " > Free</ option >
162
158
< option value = "16:9" > 16:9</ option >
163
159
< option value = "3:2" > 3:2</ option >
164
160
< option value = "4:3" > 4:3</ option >
165
- < option value = "1:1" > 1:1 (Square) </ option >
161
+ < option value = "1:1" > 1:1</ option >
166
162
< option value = "3:4" > 3:4</ option >
167
- < option value = "2:3" > 2:3 (Portrait) </ option >
168
- < option value = "9:16" > 9:16 (Portrait) </ option >
163
+ < option value = "2:3" > 2:3</ option >
164
+ < option value = "9:16" > 9:16</ option >
169
165
</ Select >
170
166
</ FormControl >
171
167
@@ -184,7 +180,7 @@ export const EditorContainer = ({ editor, onApplyCrop, onReady }: Props) => {
184
180
< Button onClick = { handleApplyCrop } > Apply</ Button >
185
181
< Button onClick = { handleResetCrop } > Reset</ Button >
186
182
< Button onClick = { handleCancelCrop } > Cancel</ Button >
187
- < Button onClick = { handleExport } > Export </ Button >
183
+ < Button onClick = { handleExport } > Save to Assets </ Button >
188
184
</ ButtonGroup >
189
185
</ Flex >
190
186
@@ -212,4 +208,6 @@ export const EditorContainer = ({ editor, onApplyCrop, onReady }: Props) => {
212
208
</ Flex >
213
209
</ Flex >
214
210
) ;
215
- } ;
211
+ } ) ;
212
+
213
+ CropImageEditor . displayName = 'CropImageEditor' ;
0 commit comments