2
2
// https://github.com/alexkrkn/react-crop-video/
3
3
// https://www.youtube.com/watch?v=vDxZLN6FVqY
4
4
5
- import { animated , useSpring } from '@react-spring/web' ;
6
- import type { EventTypes , Handler , UserDragConfig } from '@use-gesture/react' ;
7
- import { useDrag } from '@use-gesture/react' ;
8
- import isNil from 'lodash-es/isNil.js' ;
9
- import type { ReactNode , RefObject } from 'react' ;
10
- import { useCallback , useMemo , useRef } from 'react' ;
5
+ import type { ReactNode } from 'react' ;
6
+ import { useState } from 'react' ;
7
+ import { DraggableItem } from '../draggable/draggable-item.jsx' ;
11
8
12
9
export interface Grid4Props {
13
10
/**
14
11
* The dimension for the grid.
15
12
*/
16
- dimensions : {
13
+ boundary : {
17
14
/**
18
15
* The max height of the grid in pixels.
19
16
*/
@@ -25,196 +22,54 @@ export interface Grid4Props {
25
22
} ;
26
23
}
27
24
28
- // We need to invoke our pointer event handlers from different event listeners
29
- // that each have their own unique interface. Rather than force cast the events
30
- // to the desired interface, which may introduce a bug later, we'll create
31
- // a simplified interface that can be used from any event listener.
32
- export interface GridPointerEvent {
33
- clientX : number ;
34
- clientY : number ;
35
- }
36
-
37
- const GridItem4 : React . FC < Grid4Props > = ( props : Grid4Props ) : ReactNode => {
38
- const { dimensions : gridDimensions } = props ;
39
-
40
- const [ { x, y, width, height } , api ] = useSpring ( ( ) => ( {
41
- x : 0 ,
42
- y : 0 ,
43
- width : 100 ,
44
- height : 100 ,
45
- } ) ) ;
46
-
47
- const draggableRef = useRef < HTMLDivElement > ( null ) ;
48
- const resizableRef = useRef < HTMLDivElement > ( null ) ;
49
-
50
- const isEventTarget = useCallback (
51
- (
52
- eventOrTarget : Event | EventTarget | null | undefined ,
53
- ref : RefObject < HTMLElement >
54
- ) => {
55
- if ( isNil ( eventOrTarget ) ) {
56
- return false ;
57
- }
58
- if ( 'target' in eventOrTarget ) {
59
- return eventOrTarget . target === ref . current ;
60
- }
61
- return eventOrTarget === ref . current ;
62
- } ,
63
- [ ]
64
- ) ;
65
-
66
- const isDragging = useCallback (
67
- ( eventOrTarget : Event | EventTarget | null | undefined ) : boolean => {
68
- return isEventTarget ( eventOrTarget , draggableRef ) ;
69
- } ,
70
- [ isEventTarget ]
71
- ) ;
72
-
73
- const isResizing = useCallback (
74
- ( eventOrTarget : Event | EventTarget | null | undefined ) : boolean => {
75
- return isEventTarget ( eventOrTarget , resizableRef ) ;
76
- } ,
77
- [ isEventTarget ]
78
- ) ;
79
-
80
- const dragHandler : Handler < 'drag' , EventTypes [ 'drag' ] > = useCallback (
81
- /**
82
- * Callback to invoke when a gesture event ends.
83
- * For example, when the user stops dragging or resizing.
84
- */
85
- ( state ) => {
86
- // The cumulative displacements the pointer has moved relative to
87
- // the last vector returned by the `from` drag option function.
88
- const [ dx , dy ] = state . offset ;
89
-
90
- if ( isResizing ( state . event ) ) {
91
- // When resizing, the values are the new width and height dimensions.
92
- api . set ( {
93
- width : dx ,
94
- height : dy ,
95
- } ) ;
96
- } else if ( isDragging ( state . event ) ) {
97
- // When dragging, the values are the new x and y coordinates.
98
- api . set ( {
99
- x : dx ,
100
- y : dy ,
101
- } ) ;
102
- }
103
- } ,
104
- [ api , isResizing , isDragging ]
25
+ export const Grid4 : React . FC < Grid4Props > = ( props : Grid4Props ) : ReactNode => {
26
+ const { boundary } = props ;
27
+
28
+ const [ focusedItemId , setFocusedItemId ] = useState < string > ( '' ) ;
29
+
30
+ const item1 = (
31
+ < DraggableItem
32
+ key = "1"
33
+ itemId = "1"
34
+ titleBarText = "Item 1"
35
+ isFocused = { focusedItemId === '1' }
36
+ onFocus = { setFocusedItemId }
37
+ onClose = { ( ) => {
38
+ alert ( 'Closed item 1' ) ;
39
+ } }
40
+ boundary = { boundary }
41
+ >
42
+ < div > Content1</ div >
43
+ </ DraggableItem >
105
44
) ;
106
45
107
- const dragOptions : UserDragConfig = useMemo ( ( ) => {
108
- return {
109
- /**
110
- * When a gesture event begins, specify the reference vector
111
- * from which to calculate the distance the pointer moves.
112
- */
113
- from : ( state ) => {
114
- if ( isResizing ( state . target ) ) {
115
- return [ width . get ( ) , height . get ( ) ] ;
116
- }
117
- return [ x . get ( ) , y . get ( ) ] ;
118
- } ,
119
- /**
120
- * When a gesture event begins, specify the where the pointer can move.
121
- * The element will not be dragged or resized outside of these bounds.
122
- */
123
- bounds : ( state ) => {
124
- const containerWidth = gridDimensions . width ;
125
- const containerHeight = gridDimensions . height ;
126
- if ( isResizing ( state ?. event ) ) {
127
- return {
128
- top : 50 , // min height
129
- left : 50 , // min width
130
- right : containerWidth - x . get ( ) ,
131
- bottom : containerHeight - y . get ( ) ,
132
- } ;
133
- }
134
- return {
135
- top : 0 ,
136
- left : 0 ,
137
- right : containerWidth - width . get ( ) ,
138
- bottom : containerHeight - height . get ( ) ,
139
- } ;
140
- } ,
141
- } ;
142
- } , [ x , y , width , height , gridDimensions , isResizing ] ) ;
143
-
144
- const bind = useDrag ( dragHandler , dragOptions ) ;
145
-
146
- return (
147
- < animated . div
148
- style = { {
149
- position : 'absolute' ,
150
- x,
151
- y,
152
- width,
153
- height,
154
- backgroundColor : 'brown' ,
155
- overflow : 'hidden' ,
46
+ const item2 = (
47
+ < DraggableItem
48
+ key = "2"
49
+ itemId = "2"
50
+ titleBarText = "Item 2"
51
+ isFocused = { focusedItemId === '2' }
52
+ onFocus = { setFocusedItemId }
53
+ onClose = { ( ) => {
54
+ alert ( 'Closed item 2' ) ;
156
55
} }
157
- { ... bind ( ) }
56
+ boundary = { boundary }
158
57
>
159
- < div
160
- ref = { draggableRef }
161
- style = { {
162
- width : '100%' ,
163
- height : '20px' ,
164
- cursor : 'move' ,
165
- backgroundColor : 'red' ,
166
- textAlign : 'center' ,
167
- } }
168
- >
169
- Drag Handle
170
- </ div >
171
-
172
- < div
173
- style = { {
174
- width : '100%' ,
175
- height : '100%' ,
176
- overflowY : 'auto' ,
177
- overflowX : 'hidden' ,
178
- } }
179
- >
180
- This quick brown fox jumped over the fence.
181
- </ div >
182
-
183
- < div
184
- ref = { resizableRef }
185
- style = { {
186
- position : 'absolute' ,
187
- bottom : - 4 ,
188
- right : - 4 ,
189
- width : 10 ,
190
- height : 10 ,
191
- cursor : 'nwse-resize' ,
192
- backgroundColor : '#0097df' ,
193
- borderRadius : 4 ,
194
- } }
195
- > </ div >
196
- </ animated . div >
58
+ < div > Content2</ div >
59
+ </ DraggableItem >
197
60
) ;
198
- } ;
199
-
200
- GridItem4 . displayName = 'GridItem4' ;
201
-
202
- export const Grid4 : React . FC < Grid4Props > = ( props : Grid4Props ) : ReactNode => {
203
- const gridDimensions = props . dimensions ;
204
61
205
62
return (
206
63
< div
207
64
style = { {
208
- position : 'relative' ,
209
- height : gridDimensions . height ,
210
- width : gridDimensions . width ,
211
65
overflow : 'hidden' ,
66
+ position : 'relative' ,
67
+ height : boundary . height ,
68
+ width : boundary . width ,
212
69
} }
213
70
>
214
- < GridItem4 dimensions = { gridDimensions } />
215
- < GridItem4 dimensions = { gridDimensions } />
71
+ { item1 }
72
+ { item2 }
216
73
</ div >
217
74
) ;
218
75
} ;
219
-
220
- Grid4 . displayName = 'Grid4' ;
0 commit comments