1+ /* @flow strict */
2+
13const tmpl = document . createElement ( 'template' )
24tmpl . innerHTML = `
35 <div class="crop-wrapper">
@@ -14,8 +16,10 @@ tmpl.innerHTML = `
1416 </div>
1517`
1618
17- function moveCropArea ( event ) {
19+ function moveCropArea ( event : MouseEvent | KeyboardEvent ) {
1820 const el = event . currentTarget
21+ if ( ! ( el instanceof ImageCropElement ) ) return
22+
1923 let deltaX = 0
2024 let deltaY = 0
2125 if ( event . type === 'keydown' ) {
@@ -28,7 +32,7 @@ function moveCropArea(event) {
2832 } else if ( event . key === 'ArrowRight' ) {
2933 deltaX = 1
3034 }
31- } else if ( el . dragStartX && el . dragStartY ) {
35+ } else if ( el . dragStartX && el . dragStartY && event instanceof MouseEvent ) {
3236 deltaX = event . pageX - el . dragStartX
3337 deltaY = event . pageY - el . dragStartY
3438 }
@@ -42,12 +46,19 @@ function moveCropArea(event) {
4246 fireChangeEvent ( el , { x, y, width : el . box . offsetWidth , height : el . box . offsetHeight } )
4347 }
4448
45- el . dragStartX = event . pageX
46- el . dragStartY = event . pageY
49+ if ( event instanceof MouseEvent ) {
50+ el . dragStartX = event . pageX
51+ el . dragStartY = event . pageY
52+ }
4753}
4854
49- function updateCropArea ( event ) {
50- const el = event . target . closest ( 'image-crop' )
55+ function updateCropArea ( event : MouseEvent | KeyboardEvent ) {
56+ const target = event . target
57+ if ( ! ( target instanceof HTMLElement ) ) return
58+
59+ const el = target . closest ( 'image-crop' )
60+ if ( ! ( el instanceof ImageCropElement ) ) return
61+
5162 const rect = el . getBoundingClientRect ( )
5263 let deltaX , deltaY , delta
5364 if ( event . key ) {
@@ -59,18 +70,26 @@ function updateCropArea(event) {
5970 deltaY = el . box . offsetHeight + delta
6071 el . startX = el . box . offsetLeft
6172 el . startY = el . box . offsetTop
62- } else {
73+ } else if ( event instanceof MouseEvent ) {
6374 deltaX = event . pageX - el . startX - rect . left - window . pageXOffset
6475 deltaY = event . pageY - el . startY - rect . top - window . pageYOffset
6576 }
6677
67- if ( deltaX && deltaY ) updateDimensions ( el , deltaX , deltaY , ! event . key )
78+ if ( deltaX && deltaY ) updateDimensions ( el , deltaX , deltaY , ! ( event instanceof KeyboardEvent ) )
6879}
6980
70- function startUpdate ( event ) {
71- const el = event . currentTarget . closest ( 'image-crop' )
72- if ( event . target . hasAttribute ( 'data-direction' ) ) {
73- const direction = event . target . getAttribute ( 'data-direction' )
81+ function startUpdate ( event : MouseEvent ) {
82+ const currentTarget = event . currentTarget
83+ if ( ! ( currentTarget instanceof HTMLElement ) ) return
84+
85+ const el = currentTarget . closest ( 'image-crop' )
86+ if ( ! ( el instanceof ImageCropElement ) ) return
87+
88+ const target = event . target
89+ if ( ! ( target instanceof HTMLElement ) ) return
90+
91+ if ( target . hasAttribute ( 'data-direction' ) ) {
92+ const direction = target . getAttribute ( 'data-direction' )
7493 // Change crop area
7594 el . addEventListener ( 'mousemove' , updateCropArea )
7695 if ( [ 'nw' , 'se' ] . indexOf ( direction ) >= 0 ) el . classList . add ( 'nwse' )
@@ -107,8 +126,13 @@ function updateDimensions(target, deltaX, deltaY, reposition = true) {
107126 fireChangeEvent ( target , { x, y, width : newSide , height : newSide } )
108127}
109128
110- function imageReady ( event ) {
111- const el = event . currentTarget . closest ( 'image-crop' )
129+ function imageReady ( event : Event ) {
130+ const currentTarget = event . currentTarget
131+ if ( ! ( currentTarget instanceof HTMLElement ) ) return
132+
133+ const el = currentTarget . closest ( 'image-crop' )
134+ if ( ! ( el instanceof ImageCropElement ) ) return
135+
112136 el . loaded = true
113137 setInitialPosition ( el )
114138}
@@ -121,31 +145,40 @@ function setInitialPosition(el) {
121145 updateDimensions ( el , side , side )
122146}
123147
124- function stopUpdate ( event ) {
148+ function stopUpdate ( event : MouseEvent ) {
125149 const el = event . currentTarget
150+ if ( ! ( el instanceof ImageCropElement ) ) return
151+
126152 el . dragStartX = el . dragStartY = null
127153 el . classList . remove ( 'nwse' , 'nesw' )
128154 el . removeEventListener ( 'mousemove' , updateCropArea )
129155 el . removeEventListener ( 'mousemove' , moveCropArea )
130156}
131157
132- function fireChangeEvent ( target , result ) {
158+ function fireChangeEvent ( target : ImageCropElement , result : { x : number , y : number , width : number , height : number } ) {
133159 const ratio = target . image . naturalWidth / target . image . width
134160 for ( const key in result ) {
135161 const value = Math . round ( result [ key ] * ratio )
136162 result [ key ] = value
137163 const slottedInput = target . querySelector ( `[data-image-crop-input='${ key } ']` )
138- if ( slottedInput ) slottedInput . value = value
164+ if ( slottedInput instanceof HTMLInputElement ) slottedInput . value = value . toString ( )
139165 }
140166
141167 target . dispatchEvent ( new CustomEvent ( 'image-crop-change' , { bubbles : true , detail : result } ) )
142168}
143169
144170export class ImageCropElement extends HTMLElement {
171+ image : HTMLImageElement
172+ box : HTMLElement
173+ constructed : boolean
174+ minWidth : number
175+ dragStartX : ?number
176+ dragStartY : ?number
177+ startX : number
178+ startY : number
179+
145180 constructor ( ) {
146181 super ( )
147- this . startX = null
148- this . startY = null
149182 this . minWidth = 10
150183 }
151184
@@ -154,8 +187,13 @@ export class ImageCropElement extends HTMLElement {
154187 this . constructed = true
155188
156189 this . appendChild ( document . importNode ( tmpl . content , true ) )
157- this . image = this . querySelector ( 'img' )
158- this . box = this . querySelector ( '[data-crop-box]' )
190+ const image = this . querySelector ( 'img' )
191+ if ( ! ( image instanceof HTMLImageElement ) ) return
192+ this . image = image
193+
194+ const box = this . querySelector ( '[data-crop-box]' )
195+ if ( ! ( box instanceof HTMLElement ) ) return
196+ this . box = box
159197
160198 this . image . addEventListener ( 'load' , imageReady )
161199 this . addEventListener ( 'mouseleave' , stopUpdate )
@@ -171,31 +209,31 @@ export class ImageCropElement extends HTMLElement {
171209 return [ 'src' ]
172210 }
173211
174- get src ( ) {
212+ get src ( ) : ? string {
175213 return this . getAttribute ( 'src' )
176214 }
177215
178- set src ( val ) {
216+ set src ( val : ? string ) {
179217 if ( val ) {
180218 this . setAttribute ( 'src' , val )
181219 } else {
182220 this . removeAttribute ( 'src' )
183221 }
184222 }
185223
186- get loaded ( ) {
224+ get loaded ( ) : boolean {
187225 return this . hasAttribute ( 'loaded' )
188226 }
189227
190- set loaded ( val ) {
228+ set loaded ( val : boolean ) {
191229 if ( val ) {
192230 this . setAttribute ( 'loaded' , '' )
193231 } else {
194232 this . removeAttribute ( 'loaded' )
195233 }
196234 }
197235
198- attributeChangedCallback ( attribute , oldValue , newValue ) {
236+ attributeChangedCallback ( attribute : string , oldValue : string , newValue : string ) {
199237 if ( attribute === 'src' ) {
200238 this . loaded = false
201239 if ( this . image ) this . image . src = newValue
0 commit comments