@fto-consult/expo-ui 2.5.0 → 2.5.2

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.
@@ -0,0 +1,809 @@
1
+ // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ /***Fork of https://github.com/CaptainOmega/react-native-drag-resize components */
6
+ import {defaultStr,defaultObj,isObj} from "$utils";
7
+ import React, {Component} from 'react';
8
+ import {
9
+ Dimensions,
10
+ View,
11
+ TouchableWithoutFeedback,
12
+ } from 'react-native';
13
+ import PropTypes from 'prop-types';
14
+
15
+ import {
16
+ Connector,
17
+ CONNECTOR_TOP_LEFT,
18
+ CONNECTOR_TOP_MIDDLE,
19
+ CONNECTOR_TOP_RIGHT,
20
+ CONNECTOR_MIDDLE_RIGHT,
21
+ CONNECTOR_BOTTOM_RIGHT,
22
+ CONNECTOR_BOTTOM_MIDDLE,
23
+ CONNECTOR_BOTTOM_LEFT,
24
+ CONNECTOR_MIDDLE_LEFT,
25
+ CONNECTOR_CENTER
26
+ } from './Connector';
27
+
28
+ export const AXIS_X = 'x';
29
+ export const AXIS_Y = 'y';
30
+ export const AXIS_ALL = 'all';
31
+
32
+ const CONNECTOR_SIZE = 14;
33
+ const DEFAULT_Z_INDEX = 1;
34
+
35
+ /**
36
+ * Drag resize block.
37
+ */
38
+ export class DragResizeBlock extends Component {
39
+
40
+ constructor(props) {
41
+ super(props);
42
+
43
+ const {
44
+ x,
45
+ y,
46
+ w,
47
+ h,
48
+ minW,
49
+ minH,
50
+ } = props;
51
+
52
+ this.state = {
53
+ isSelected: false,
54
+ x,
55
+ y,
56
+ w: w < minW ? minW : w,
57
+ h: h < minH ? minH : h,
58
+ };
59
+
60
+ /**
61
+ * Connectors binding.
62
+ */
63
+ this.connectorsMap = {};
64
+
65
+ /**
66
+ * Top left connector.
67
+ */
68
+ this.connectorsMap[CONNECTOR_TOP_LEFT] = {
69
+ calculateX: (width) => {
70
+ return 0;
71
+ },
72
+ calculateY: (height) => {
73
+ return 0;
74
+ },
75
+ onStart: this.onResizeStart,
76
+ onMove: this.onResizeTL,
77
+ onEnd: this.onResizeEnd,
78
+ };
79
+
80
+ /**
81
+ * Top middle connector.
82
+ */
83
+ this.connectorsMap[CONNECTOR_TOP_MIDDLE] = {
84
+ calculateX: (width) => {
85
+ return width / 2 - CONNECTOR_SIZE / 2;
86
+ },
87
+ calculateY: (height) => {
88
+ return 0;
89
+ },
90
+ onStart: this.onResizeStart,
91
+ onMove: this.onResizeTM,
92
+ onEnd: this.onResizeEnd,
93
+ };
94
+
95
+ /**
96
+ * Top right connector.
97
+ */
98
+ this.connectorsMap[CONNECTOR_TOP_RIGHT] = {
99
+ calculateX: (width) => {
100
+ return width - CONNECTOR_SIZE;
101
+ },
102
+ calculateY: (height) => {
103
+ return 0;
104
+ },
105
+ onStart: this.onResizeStart,
106
+ onMove: this.onResizeTR,
107
+ onEnd: this.onResizeEnd,
108
+ };
109
+
110
+ /**
111
+ * Middle right connector.
112
+ */
113
+ this.connectorsMap[CONNECTOR_MIDDLE_RIGHT] = {
114
+ calculateX: (width) => {
115
+ return width - CONNECTOR_SIZE;
116
+ },
117
+ calculateY: (height) => {
118
+ return height / 2 - CONNECTOR_SIZE / 2;
119
+ },
120
+ onStart: this.onResizeStart,
121
+ onMove: this.onResizeMR,
122
+ onEnd: this.onResizeEnd,
123
+ };
124
+
125
+ /**
126
+ * Bottom right connector.
127
+ */
128
+ this.connectorsMap[CONNECTOR_BOTTOM_RIGHT] = {
129
+ calculateX: (width) => {
130
+ return width - CONNECTOR_SIZE;
131
+ },
132
+ calculateY: (height) => {
133
+ return height - CONNECTOR_SIZE;
134
+ },
135
+ onStart: this.onResizeStart,
136
+ onMove: this.onResizeBR,
137
+ onEnd: this.onResizeEnd,
138
+ };
139
+
140
+ /**
141
+ * Bottom middle connector.
142
+ */
143
+ this.connectorsMap[CONNECTOR_BOTTOM_MIDDLE] = {
144
+ calculateX: (width) => {
145
+ return width / 2 - CONNECTOR_SIZE / 2;
146
+ },
147
+ calculateY: (height) => {
148
+ return height - CONNECTOR_SIZE;
149
+ },
150
+ onStart: this.onResizeStart,
151
+ onMove: this.onResizeBM,
152
+ onEnd: this.onResizeEnd,
153
+ };
154
+
155
+ /**
156
+ * Bottom left connector.
157
+ */
158
+ this.connectorsMap[CONNECTOR_BOTTOM_LEFT] = {
159
+ calculateX: (width) => {
160
+ return 0;
161
+ },
162
+ calculateY: (height) => {
163
+ return height - CONNECTOR_SIZE;
164
+ },
165
+ onStart: this.onResizeStart,
166
+ onMove: this.onResizeBL,
167
+ onEnd: this.onResizeEnd,
168
+ };
169
+
170
+ /**
171
+ * Middle left connector.
172
+ */
173
+ this.connectorsMap[CONNECTOR_MIDDLE_LEFT] = {
174
+ calculateX: (width) => {
175
+ return 0;
176
+ },
177
+ calculateY: (height) => {
178
+ return height / 2 - CONNECTOR_SIZE / 2;
179
+ },
180
+ onStart: this.onResizeStart,
181
+ onMove: this.onResizeML,
182
+ onEnd: this.onResizeEnd,
183
+ };
184
+
185
+ /**
186
+ * Center connector.
187
+ */
188
+ this.connectorsMap[CONNECTOR_CENTER] = {
189
+ calculateX: (width) => {
190
+ return width / 2 - CONNECTOR_SIZE / 2;
191
+ },
192
+ calculateY: (height) => {
193
+ return height / 2 - CONNECTOR_SIZE / 2;
194
+ },
195
+ onStart: this.onDragStart,
196
+ onMove: this.onDrag,
197
+ onEnd: this.onDragEnd,
198
+ };
199
+ }
200
+
201
+ /**
202
+ * Handle press event.
203
+ * @param {Event} event - Press event.
204
+ */
205
+ onPress = (event) => {
206
+ const {
207
+ onPress,
208
+ } = this.props;
209
+
210
+ if (onPress !== null) {
211
+ onPress(event);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Handle resize start event.
217
+ * @param {Array} coord - Press coordinate [x,y].
218
+ */
219
+ onResizeStart = (coord) => {
220
+ const {
221
+ onResizeStart,
222
+ } = this.props;
223
+
224
+ this.setState(() => {
225
+ return {
226
+ isSelected: true,
227
+ };
228
+ });
229
+
230
+ if (onResizeStart !== null) {
231
+ onResizeStart([
232
+ this.state.x,
233
+ this.state.y,
234
+ ]);
235
+ }
236
+ }
237
+
238
+ onResizeTL = (coord) => {
239
+ const {
240
+ minW,
241
+ minH,
242
+ axis,
243
+ resizable,
244
+ limitation,
245
+ onResize,
246
+ } = this.props;
247
+
248
+ if (!resizable) {
249
+ return;
250
+ }
251
+
252
+ this.setState(() => {
253
+ const newX = this.state.x + coord[0];
254
+ const newY = this.state.y + coord[1];
255
+ const newW = this.state.x + this.state.w - newX;
256
+ const newH = this.state.y + this.state.h - newY;
257
+
258
+ if (newW >= minW && axis != AXIS_Y) {
259
+ if (limitation.x <= newX) {
260
+ this.state.w = newW;
261
+ this.state.x = newX;
262
+ }
263
+ }
264
+
265
+ if (newH >= minH && axis != AXIS_X) {
266
+ if (limitation.y <= newY) {
267
+ this.state.h = newH;
268
+ this.state.y = newY;
269
+ }
270
+ }
271
+
272
+ if (onResize !== null) {
273
+ onResize([
274
+ this.state.x,
275
+ this.state.y,
276
+ ]);
277
+ }
278
+
279
+ return this.state;
280
+ });
281
+ }
282
+
283
+ onResizeTM = (coord) => {
284
+ const {
285
+ minH,
286
+ axis,
287
+ resizable,
288
+ limitation,
289
+ onResize,
290
+ } = this.props;
291
+
292
+ if (!resizable) {
293
+ return;
294
+ }
295
+
296
+ this.setState(() => {
297
+ const newY = this.state.y + coord[1];
298
+ const newH = this.state.y + this.state.h - newY;
299
+
300
+ if (newH >= minH && axis != AXIS_X) {
301
+ if (limitation.y <= newY) {
302
+ this.state.h = newH;
303
+ this.state.y = newY;
304
+ }
305
+ }
306
+
307
+ if (onResize !== null) {
308
+ onResize([
309
+ this.state.x,
310
+ this.state.y,
311
+ ]);
312
+ }
313
+
314
+ return this.state;
315
+ });
316
+ }
317
+
318
+ onResizeTR = (coord) => {
319
+ const {
320
+ minW,
321
+ minH,
322
+ axis,
323
+ resizable,
324
+ limitation,
325
+ onResize,
326
+ } = this.props;
327
+
328
+ if (!resizable) {
329
+ return;
330
+ }
331
+
332
+ this.setState(() => {
333
+ const newY = this.state.y + coord[1];
334
+ const newW = this.state.w + coord[0];
335
+ const newH = this.state.y + this.state.h - newY;
336
+
337
+ if (newW >= minW && axis != AXIS_Y) {
338
+ if (limitation.w >= this.state.x + newW) {
339
+ this.state.w = newW;
340
+ }
341
+ }
342
+
343
+ if (newH >= minH && axis != AXIS_X) {
344
+ if (limitation.y <= newY) {
345
+ this.state.h = newH;
346
+ this.state.y = newY;
347
+ }
348
+ }
349
+
350
+ if (onResize !== null) {
351
+ onResize([
352
+ this.state.x,
353
+ this.state.y,
354
+ ]);
355
+ }
356
+
357
+ return this.state;
358
+ });
359
+ }
360
+
361
+ onResizeMR = (coord) => {
362
+ const {
363
+ minW,
364
+ axis,
365
+ resizable,
366
+ limitation,
367
+ onResize,
368
+ } = this.props;
369
+
370
+ if (!resizable) {
371
+ return;
372
+ }
373
+
374
+ this.setState(() => {
375
+ const newW = this.state.w + coord[0];
376
+
377
+ if (newW >= minW && axis != AXIS_Y) {
378
+ if (limitation.w >= this.state.x + newW) {
379
+ this.state.w = newW;
380
+ }
381
+ }
382
+
383
+ if (onResize !== null) {
384
+ onResize([
385
+ this.state.x,
386
+ this.state.y,
387
+ ]);
388
+ }
389
+
390
+ return this.state;
391
+ });
392
+ }
393
+
394
+ onResizeBR = (coord) => {
395
+ const {
396
+ minW,
397
+ minH,
398
+ axis,
399
+ resizable,
400
+ limitation,
401
+ onResize,
402
+ } = this.props;
403
+
404
+ if (!resizable) {
405
+ return;
406
+ }
407
+
408
+ this.setState(() => {
409
+ const newW = this.state.w + coord[0];
410
+ const newH = this.state.h + coord[1];
411
+
412
+ if (newW >= minW && axis != AXIS_Y) {
413
+ if (limitation.w >= this.state.x + newW) {
414
+ this.state.w = newW;
415
+ }
416
+ }
417
+
418
+ if (newH >= minH && axis != AXIS_X) {
419
+ if (limitation.h >= this.state.y + newH) {
420
+ this.state.h = newH;
421
+ }
422
+ }
423
+
424
+ if (onResize !== null) {
425
+ onResize([
426
+ this.state.x,
427
+ this.state.y,
428
+ ]);
429
+ }
430
+
431
+ return this.state;
432
+ });
433
+ }
434
+
435
+ onResizeBM = (coord) => {
436
+ const {
437
+ minH,
438
+ axis,
439
+ resizable,
440
+ limitation,
441
+ onResize,
442
+ } = this.props;
443
+
444
+ if (!resizable) {
445
+ return;
446
+ }
447
+
448
+ this.setState(() => {
449
+ const newH = this.state.h + coord[1];
450
+
451
+ if (newH >= minH && axis != AXIS_X) {
452
+ if (limitation.h >= this.state.y + newH) {
453
+ this.state.h = newH;
454
+ }
455
+ }
456
+
457
+ if (onResize !== null) {
458
+ onResize([
459
+ this.state.x,
460
+ this.state.y,
461
+ ]);
462
+ }
463
+
464
+ return this.state;
465
+ });
466
+ }
467
+
468
+ onResizeBL = (coord) => {
469
+ const {
470
+ minW,
471
+ minH,
472
+ axis,
473
+ resizable,
474
+ limitation,
475
+ onResize,
476
+ } = this.props;
477
+
478
+ if (!resizable) {
479
+ return;
480
+ }
481
+
482
+ this.setState(() => {
483
+ const newX = this.state.x + coord[0];
484
+ const newW = this.state.x + this.state.w - newX;
485
+ const newH = this.state.h + coord[1];
486
+
487
+ if (newW >= minW && axis != AXIS_Y) {
488
+ if (limitation.x <= newX) {
489
+ this.state.w = newW;
490
+ this.state.x = newX;
491
+ }
492
+ }
493
+
494
+ if (newH >= minH && axis != AXIS_X) {
495
+ if (this.state.y + newH <= limitation.h) {
496
+ this.state.h = newH;
497
+ }
498
+ }
499
+
500
+ if (onResize !== null) {
501
+ onResize([
502
+ this.state.x,
503
+ this.state.y,
504
+ ]);
505
+ }
506
+
507
+ return this.state;
508
+ });
509
+ }
510
+
511
+ onResizeML = (coord) => {
512
+ const {
513
+ minW,
514
+ axis,
515
+ resizable,
516
+ limitation,
517
+ onResize,
518
+ } = this.props;
519
+
520
+ if (!resizable) {
521
+ return;
522
+ }
523
+
524
+ this.setState(() => {
525
+ const newX = this.state.x + coord[0];
526
+ const newW = this.state.x + this.state.w - newX;
527
+
528
+ if (newW >= minW && axis != AXIS_Y) {
529
+ if (limitation.x <= newX) {
530
+ this.state.w = newW;
531
+ this.state.x = newX;
532
+ }
533
+ }
534
+
535
+ if (onResize !== null) {
536
+ onResize([
537
+ this.state.x,
538
+ this.state.y,
539
+ ]);
540
+ }
541
+
542
+ return this.state;
543
+ });
544
+ }
545
+
546
+ /**
547
+ * Handle resize end event.
548
+ * @param {Array} coord - Press coordinate [x,y].
549
+ */
550
+ onResizeEnd = (coord) => {
551
+ const {
552
+ onResizeEnd,
553
+ } = this.props;
554
+
555
+ this.setState(() => {
556
+ return {
557
+ isSelected: false,
558
+ };
559
+ });
560
+
561
+ if (onResizeEnd !== null) {
562
+ onResizeEnd([
563
+ this.state.x,
564
+ this.state.y,
565
+ ]);
566
+ }
567
+ }
568
+
569
+ /**
570
+ * Handle drag start event.
571
+ * @param {Array} coord - Press coordinate [x,y].
572
+ */
573
+ onDragStart = (coord) => {
574
+ const {
575
+ onDragStart,
576
+ } = this.props;
577
+
578
+ this.setState(() => {
579
+ return {
580
+ isSelected: true,
581
+ };
582
+ });
583
+
584
+ if (onDragStart !== null) {
585
+ onDragStart([
586
+ this.state.x,
587
+ this.state.y,
588
+ ]);
589
+ }
590
+ }
591
+
592
+ /**
593
+ * Handle drag event.
594
+ * @param {Array} coord - Press coordinate [x,y].
595
+ */
596
+ onDrag = (coord) => {
597
+ const {
598
+ axis,
599
+ draggable,
600
+ limitation,
601
+ onDrag,
602
+ } = this.props;
603
+
604
+ if (!draggable) {
605
+ return;
606
+ }
607
+
608
+ this.setState(() => {
609
+ const newX = this.state.x + coord[0];
610
+ const newY = this.state.y + coord[1];
611
+
612
+ if (axis != AXIS_Y) {
613
+ if (limitation.x <= newX && limitation.w >= newX + this.state.w) {
614
+ this.state.x = newX;
615
+ }
616
+ }
617
+
618
+ if (axis != AXIS_X) {
619
+ if (limitation.y <= newY && limitation.h >= newY + this.state.h) {
620
+ this.state.y = newY;
621
+ }
622
+ }
623
+
624
+ if (onDrag !== null) {
625
+ onDrag([
626
+ this.state.x,
627
+ this.state.y,
628
+ ]);
629
+ }
630
+
631
+ return this.state;
632
+ });
633
+ }
634
+
635
+ /**
636
+ * Handle drag end event.
637
+ * @param {Array} coord - Press coordinate [x,y].
638
+ */
639
+ onDragEnd = (coord) => {
640
+ const {
641
+ onDragEnd,
642
+ } = this.props;
643
+
644
+ this.setState(() => {
645
+ return {
646
+ isSelected: false,
647
+ };
648
+ });
649
+
650
+ if (onDragEnd !== null) {
651
+ onDragEnd([
652
+ this.state.x,
653
+ this.state.y,
654
+ ]);
655
+ }
656
+ }
657
+
658
+ /**
659
+ * Render connector components.
660
+ */
661
+ renderConnectors = () => {
662
+ const {
663
+ connectors,
664
+ } = this.props;
665
+ const {
666
+ w,
667
+ h,
668
+ } = this.state;
669
+ return connectors.map((connectorType) => {
670
+ return (
671
+ <Connector
672
+ key={connectorType}
673
+ type={connectorType}
674
+ size={CONNECTOR_SIZE}
675
+ x={this.connectorsMap[connectorType].calculateX(w)}
676
+ y={this.connectorsMap[connectorType].calculateY(h)}
677
+ onStart={this.connectorsMap[connectorType].onStart}
678
+ onMove={this.connectorsMap[connectorType].onMove}
679
+ onEnd={this.connectorsMap[connectorType].onEnd}
680
+ />
681
+ );
682
+ });
683
+ }
684
+
685
+ render() {
686
+ const {
687
+ children,
688
+ isDisabled,
689
+ zIndex,
690
+ } = this.props;
691
+ const testID = defaultStr(this.props.testID,"RN_ReactNativeResizeBlockComponent")
692
+ const contentProps = defaultObj(this.props.contentProps);
693
+ const containerProps = defaultObj(this.props.contentProps);
694
+ const {
695
+ x,
696
+ y,
697
+ w,
698
+ h,
699
+ isSelected,
700
+ } = this.state;
701
+
702
+ return (
703
+ <View
704
+ {...containerProps}
705
+ style={[{
706
+ position: 'absolute',
707
+ left: x,
708
+ top: y,
709
+ width: w,
710
+ height: h,
711
+ padding: CONNECTOR_SIZE / 2,
712
+ zIndex: isSelected ? zIndex + 1 : zIndex,
713
+ },containerProps.style]}
714
+ testID = {testID}
715
+ >
716
+ <TouchableWithoutFeedback
717
+ onPress={this.onPress}
718
+ testID = {testID+"_TouchableFeedBack"}
719
+ >
720
+ <View
721
+ testID={testID+"_Content"}
722
+ {...contentProps}
723
+ style={[{
724
+ width: '100%',
725
+ height: '100%',
726
+ },contentProps.style]}
727
+ >
728
+ {children}
729
+ </View>
730
+ </TouchableWithoutFeedback>
731
+
732
+ {isDisabled ? null : this.renderConnectors()}
733
+
734
+ </View>
735
+ );
736
+ }
737
+ }
738
+
739
+ DragResizeBlock.defaultProps = {
740
+ x: 0,
741
+ y: 0,
742
+ w: 100,
743
+ h: 100,
744
+ minW: 50,
745
+ minH: 50,
746
+ axis: AXIS_ALL,
747
+ limitation: {
748
+ x: 0,
749
+ y: 0,
750
+ w: Dimensions.get('window').width,
751
+ h: Dimensions.get('window').height,
752
+ },
753
+ isDisabled: false,
754
+ zIndex: DEFAULT_Z_INDEX,
755
+ draggable: true,
756
+ resizable: true,
757
+ connectors: [
758
+ CONNECTOR_TOP_LEFT,
759
+ CONNECTOR_TOP_MIDDLE,
760
+ CONNECTOR_TOP_RIGHT,
761
+ CONNECTOR_MIDDLE_RIGHT,
762
+ CONNECTOR_BOTTOM_RIGHT,
763
+ CONNECTOR_BOTTOM_MIDDLE,
764
+ CONNECTOR_BOTTOM_LEFT,
765
+ CONNECTOR_MIDDLE_LEFT,
766
+ CONNECTOR_CENTER,
767
+ ],
768
+
769
+ onPress: null,
770
+ onDragStart: null,
771
+ onDrag: null,
772
+ onDragEnd: null,
773
+ onResizeStart: null,
774
+ onResize: null,
775
+ onResizeEnd: null,
776
+ };
777
+
778
+ DragResizeBlock.propTypes = {
779
+ x: PropTypes.number,
780
+ y: PropTypes.number,
781
+ w: PropTypes.number,
782
+ h: PropTypes.number,
783
+ minW: PropTypes.number,
784
+ minH: PropTypes.number,
785
+ zIndex: PropTypes.number,
786
+ axis: PropTypes.oneOf([
787
+ AXIS_X,
788
+ AXIS_Y,
789
+ AXIS_ALL,
790
+ ]),
791
+ limitation: PropTypes.shape({
792
+ x: PropTypes.number.isRequired,
793
+ y: PropTypes.number.isRequired,
794
+ w: PropTypes.number.isRequired,
795
+ h: PropTypes.number.isRequired,
796
+ }),
797
+ isDisabled: PropTypes.bool,
798
+ draggable: PropTypes.bool,
799
+ resizable: PropTypes.bool,
800
+ connectors: PropTypes.array,
801
+
802
+ onPress: PropTypes.func,
803
+ onDragStart: PropTypes.func,
804
+ onDrag: PropTypes.func,
805
+ onDragEnd: PropTypes.func,
806
+ onResizeStart: PropTypes.func,
807
+ onResize: PropTypes.func,
808
+ onResizeEnd: PropTypes.func,
809
+ };