@gfazioli/mantine-window 0.5.5 → 0.5.7

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.
@@ -106,6 +106,26 @@ function useMantineWindow(props) {
106
106
  },
107
107
  [position, bringToFront]
108
108
  );
109
+ const handleTouchStartDrag = React.useCallback(
110
+ (e) => {
111
+ if (e.target.closest("[data-resize-handle]")) {
112
+ return;
113
+ }
114
+ if (!e.touches[0]) {
115
+ return;
116
+ }
117
+ const touch = e.touches[0];
118
+ bringToFront();
119
+ isDragging.current = true;
120
+ dragStart.current = {
121
+ x: touch.clientX - position.x,
122
+ y: touch.clientY - position.y
123
+ };
124
+ document.body.style.userSelect = "none";
125
+ e.preventDefault();
126
+ },
127
+ [position, bringToFront]
128
+ );
109
129
  const resizeDirection = React.useRef("");
110
130
  const handleMouseDownResizeTopLeft = React.useCallback(
111
131
  (e) => {
@@ -127,6 +147,28 @@ function useMantineWindow(props) {
127
147
  },
128
148
  [size, position, bringToFront]
129
149
  );
150
+ const handleTouchStartResizeTopLeft = React.useCallback(
151
+ (e) => {
152
+ if (!e.touches[0]) {
153
+ return;
154
+ }
155
+ const touch = e.touches[0];
156
+ bringToFront();
157
+ isResizing.current = true;
158
+ resizeDirection.current = "topLeft";
159
+ resizeStart.current = {
160
+ x: touch.clientX,
161
+ y: touch.clientY,
162
+ width: size.width,
163
+ height: size.height,
164
+ posX: position.x,
165
+ posY: position.y
166
+ };
167
+ document.body.style.userSelect = "none";
168
+ e.stopPropagation();
169
+ },
170
+ [size, position, bringToFront]
171
+ );
130
172
  const handleMouseDownResizeTop = React.useCallback(
131
173
  (e) => {
132
174
  bringToFront();
@@ -147,6 +189,28 @@ function useMantineWindow(props) {
147
189
  },
148
190
  [size, position, bringToFront]
149
191
  );
192
+ const handleTouchStartResizeTop = React.useCallback(
193
+ (e) => {
194
+ if (!e.touches[0]) {
195
+ return;
196
+ }
197
+ const touch = e.touches[0];
198
+ bringToFront();
199
+ isResizing.current = true;
200
+ resizeDirection.current = "top";
201
+ resizeStart.current = {
202
+ x: touch.clientX,
203
+ y: touch.clientY,
204
+ width: size.width,
205
+ height: size.height,
206
+ posX: position.x,
207
+ posY: position.y
208
+ };
209
+ document.body.style.userSelect = "none";
210
+ e.stopPropagation();
211
+ },
212
+ [size, position, bringToFront]
213
+ );
150
214
  const handleMouseDownResizeTopRight = React.useCallback(
151
215
  (e) => {
152
216
  bringToFront();
@@ -167,6 +231,28 @@ function useMantineWindow(props) {
167
231
  },
168
232
  [size, position, bringToFront]
169
233
  );
234
+ const handleTouchStartResizeTopRight = React.useCallback(
235
+ (e) => {
236
+ if (!e.touches[0]) {
237
+ return;
238
+ }
239
+ const touch = e.touches[0];
240
+ bringToFront();
241
+ isResizing.current = true;
242
+ resizeDirection.current = "topRight";
243
+ resizeStart.current = {
244
+ x: touch.clientX,
245
+ y: touch.clientY,
246
+ width: size.width,
247
+ height: size.height,
248
+ posX: position.x,
249
+ posY: position.y
250
+ };
251
+ document.body.style.userSelect = "none";
252
+ e.stopPropagation();
253
+ },
254
+ [size, position, bringToFront]
255
+ );
170
256
  const handleMouseDownResizeRight = React.useCallback(
171
257
  (e) => {
172
258
  bringToFront();
@@ -187,6 +273,28 @@ function useMantineWindow(props) {
187
273
  },
188
274
  [size, position, bringToFront]
189
275
  );
276
+ const handleTouchStartResizeRight = React.useCallback(
277
+ (e) => {
278
+ if (!e.touches[0]) {
279
+ return;
280
+ }
281
+ const touch = e.touches[0];
282
+ bringToFront();
283
+ isResizing.current = true;
284
+ resizeDirection.current = "right";
285
+ resizeStart.current = {
286
+ x: touch.clientX,
287
+ y: touch.clientY,
288
+ width: size.width,
289
+ height: size.height,
290
+ posX: position.x,
291
+ posY: position.y
292
+ };
293
+ document.body.style.userSelect = "none";
294
+ e.stopPropagation();
295
+ },
296
+ [size, position, bringToFront]
297
+ );
190
298
  const handleMouseDownResizeBottomRight = React.useCallback(
191
299
  (e) => {
192
300
  bringToFront();
@@ -207,6 +315,28 @@ function useMantineWindow(props) {
207
315
  },
208
316
  [size, position, bringToFront]
209
317
  );
318
+ const handleTouchStartResizeBottomRight = React.useCallback(
319
+ (e) => {
320
+ if (!e.touches[0]) {
321
+ return;
322
+ }
323
+ const touch = e.touches[0];
324
+ bringToFront();
325
+ isResizing.current = true;
326
+ resizeDirection.current = "bottomRight";
327
+ resizeStart.current = {
328
+ x: touch.clientX,
329
+ y: touch.clientY,
330
+ width: size.width,
331
+ height: size.height,
332
+ posX: position.x,
333
+ posY: position.y
334
+ };
335
+ document.body.style.userSelect = "none";
336
+ e.stopPropagation();
337
+ },
338
+ [size, position, bringToFront]
339
+ );
210
340
  const handleMouseDownResizeBottom = React.useCallback(
211
341
  (e) => {
212
342
  bringToFront();
@@ -227,6 +357,28 @@ function useMantineWindow(props) {
227
357
  },
228
358
  [size, position, bringToFront]
229
359
  );
360
+ const handleTouchStartResizeBottom = React.useCallback(
361
+ (e) => {
362
+ if (!e.touches[0]) {
363
+ return;
364
+ }
365
+ const touch = e.touches[0];
366
+ bringToFront();
367
+ isResizing.current = true;
368
+ resizeDirection.current = "bottom";
369
+ resizeStart.current = {
370
+ x: touch.clientX,
371
+ y: touch.clientY,
372
+ width: size.width,
373
+ height: size.height,
374
+ posX: position.x,
375
+ posY: position.y
376
+ };
377
+ document.body.style.userSelect = "none";
378
+ e.stopPropagation();
379
+ },
380
+ [size, position, bringToFront]
381
+ );
230
382
  const handleMouseDownResizeBottomLeft = React.useCallback(
231
383
  (e) => {
232
384
  bringToFront();
@@ -247,6 +399,28 @@ function useMantineWindow(props) {
247
399
  },
248
400
  [size, position, bringToFront]
249
401
  );
402
+ const handleTouchStartResizeBottomLeft = React.useCallback(
403
+ (e) => {
404
+ if (!e.touches[0]) {
405
+ return;
406
+ }
407
+ const touch = e.touches[0];
408
+ bringToFront();
409
+ isResizing.current = true;
410
+ resizeDirection.current = "bottomLeft";
411
+ resizeStart.current = {
412
+ x: touch.clientX,
413
+ y: touch.clientY,
414
+ width: size.width,
415
+ height: size.height,
416
+ posX: position.x,
417
+ posY: position.y
418
+ };
419
+ document.body.style.userSelect = "none";
420
+ e.stopPropagation();
421
+ },
422
+ [size, position, bringToFront]
423
+ );
250
424
  const handleMouseDownResizeLeft = React.useCallback(
251
425
  (e) => {
252
426
  bringToFront();
@@ -267,105 +441,168 @@ function useMantineWindow(props) {
267
441
  },
268
442
  [size, position, bringToFront]
269
443
  );
444
+ const handleTouchStartResizeLeft = React.useCallback(
445
+ (e) => {
446
+ if (!e.touches[0]) {
447
+ return;
448
+ }
449
+ const touch = e.touches[0];
450
+ bringToFront();
451
+ isResizing.current = true;
452
+ resizeDirection.current = "left";
453
+ resizeStart.current = {
454
+ x: touch.clientX,
455
+ y: touch.clientY,
456
+ width: size.width,
457
+ height: size.height,
458
+ posX: position.x,
459
+ posY: position.y
460
+ };
461
+ document.body.style.userSelect = "none";
462
+ e.stopPropagation();
463
+ },
464
+ [size, position, bringToFront]
465
+ );
270
466
  const handleClose = React.useCallback(() => {
271
467
  if (onClose) {
272
468
  return onClose();
273
469
  }
274
470
  setIsVisible(false);
275
471
  }, [onClose]);
472
+ const clampWidth = React.useCallback(
473
+ (w) => {
474
+ let clamped = Math.max(minWidth, w);
475
+ if (maxWidth !== void 0) {
476
+ clamped = Math.min(maxWidth, clamped);
477
+ }
478
+ return clamped;
479
+ },
480
+ [minWidth, maxWidth]
481
+ );
482
+ const clampHeight = React.useCallback(
483
+ (h) => {
484
+ let clamped = Math.max(minHeight, h);
485
+ if (maxHeight !== void 0) {
486
+ clamped = Math.min(maxHeight, clamped);
487
+ }
488
+ return clamped;
489
+ },
490
+ [minHeight, maxHeight]
491
+ );
492
+ const applyDragBounds = React.useCallback(
493
+ (newX, newY) => {
494
+ let boundedX = newX;
495
+ let boundedY = newY;
496
+ if (dragBounds) {
497
+ if (dragBounds.minX !== void 0) {
498
+ boundedX = Math.max(dragBounds.minX, boundedX);
499
+ }
500
+ if (dragBounds.maxX !== void 0) {
501
+ boundedX = Math.min(dragBounds.maxX, boundedX);
502
+ }
503
+ if (dragBounds.minY !== void 0) {
504
+ boundedY = Math.max(dragBounds.minY, boundedY);
505
+ }
506
+ if (dragBounds.maxY !== void 0) {
507
+ boundedY = Math.min(dragBounds.maxY, boundedY);
508
+ }
509
+ } else if (withinPortal) {
510
+ boundedX = Math.max(0, Math.min(boundedX, window.innerWidth - size.width));
511
+ boundedY = Math.max(0, Math.min(boundedY, window.innerHeight - 50));
512
+ } else {
513
+ const parent = windowRef.current?.offsetParent;
514
+ if (parent instanceof HTMLElement) {
515
+ const parentWidth = parent.clientWidth;
516
+ const parentHeight = parent.clientHeight;
517
+ boundedX = Math.max(0, Math.min(boundedX, parentWidth - size.width));
518
+ boundedY = Math.max(0, Math.min(boundedY, parentHeight - 50));
519
+ }
520
+ }
521
+ return { x: boundedX, y: boundedY };
522
+ },
523
+ [dragBounds, withinPortal, size.width]
524
+ );
525
+ const handleResize = React.useCallback(
526
+ (clientX, clientY) => {
527
+ const deltaX = clientX - resizeStart.current.x;
528
+ const deltaY = clientY - resizeStart.current.y;
529
+ let newWidth = size.width;
530
+ let newHeight = size.height;
531
+ let newX = resizeStart.current.posX;
532
+ let newY = resizeStart.current.posY;
533
+ switch (resizeDirection.current) {
534
+ case "topLeft":
535
+ newWidth = clampWidth(resizeStart.current.width - deltaX);
536
+ newHeight = clampHeight(resizeStart.current.height - deltaY);
537
+ newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
538
+ newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
539
+ break;
540
+ case "top":
541
+ newHeight = clampHeight(resizeStart.current.height - deltaY);
542
+ newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
543
+ break;
544
+ case "topRight":
545
+ newWidth = clampWidth(resizeStart.current.width + deltaX);
546
+ newHeight = clampHeight(resizeStart.current.height - deltaY);
547
+ newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
548
+ break;
549
+ case "right":
550
+ newWidth = clampWidth(resizeStart.current.width + deltaX);
551
+ break;
552
+ case "bottomRight":
553
+ newWidth = clampWidth(resizeStart.current.width + deltaX);
554
+ newHeight = clampHeight(resizeStart.current.height + deltaY);
555
+ break;
556
+ case "bottom":
557
+ newHeight = clampHeight(resizeStart.current.height + deltaY);
558
+ break;
559
+ case "bottomLeft":
560
+ newWidth = clampWidth(resizeStart.current.width - deltaX);
561
+ newHeight = clampHeight(resizeStart.current.height + deltaY);
562
+ newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
563
+ break;
564
+ case "left":
565
+ newWidth = clampWidth(resizeStart.current.width - deltaX);
566
+ newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
567
+ break;
568
+ }
569
+ setSize({ width: newWidth, height: newHeight });
570
+ if (newX !== resizeStart.current.posX || newY !== resizeStart.current.posY) {
571
+ setPosition({ x: newX, y: newY });
572
+ }
573
+ },
574
+ [size.width, size.height, clampWidth, clampHeight, setSize, setPosition]
575
+ );
276
576
  React.useEffect(() => {
277
577
  const handleMouseMove = (e) => {
278
578
  if (isDragging.current) {
279
- let newX = e.clientX - dragStart.current.x;
280
- let newY = e.clientY - dragStart.current.y;
281
- if (dragBounds) {
282
- if (dragBounds.minX !== void 0) {
283
- newX = Math.max(dragBounds.minX, newX);
284
- }
285
- if (dragBounds.maxX !== void 0) {
286
- newX = Math.min(dragBounds.maxX, newX);
287
- }
288
- if (dragBounds.minY !== void 0) {
289
- newY = Math.max(dragBounds.minY, newY);
290
- }
291
- if (dragBounds.maxY !== void 0) {
292
- newY = Math.min(dragBounds.maxY, newY);
293
- }
294
- } else if (withinPortal) {
295
- newX = Math.max(0, Math.min(newX, window.innerWidth - size.width));
296
- newY = Math.max(0, Math.min(newY, window.innerHeight - 50));
297
- } else {
298
- const parent = windowRef.current?.offsetParent;
299
- if (parent instanceof HTMLElement) {
300
- const parentWidth = parent.clientWidth;
301
- const parentHeight = parent.clientHeight;
302
- newX = Math.max(0, Math.min(newX, parentWidth - size.width));
303
- newY = Math.max(0, Math.min(newY, parentHeight - 50));
304
- }
305
- }
306
- setPosition({ x: newX, y: newY });
579
+ const newPos = applyDragBounds(
580
+ e.clientX - dragStart.current.x,
581
+ e.clientY - dragStart.current.y
582
+ );
583
+ setPosition(newPos);
307
584
  }
308
585
  if (isResizing.current) {
309
- const deltaX = e.clientX - resizeStart.current.x;
310
- const deltaY = e.clientY - resizeStart.current.y;
311
- let newWidth = size.width;
312
- let newHeight = size.height;
313
- let newX = resizeStart.current.posX;
314
- let newY = resizeStart.current.posY;
315
- const clampWidth = (w) => {
316
- let clamped = Math.max(minWidth, w);
317
- if (maxWidth !== void 0) {
318
- clamped = Math.min(maxWidth, clamped);
319
- }
320
- return clamped;
321
- };
322
- const clampHeight = (h) => {
323
- let clamped = Math.max(minHeight, h);
324
- if (maxHeight !== void 0) {
325
- clamped = Math.min(maxHeight, clamped);
326
- }
327
- return clamped;
328
- };
329
- switch (resizeDirection.current) {
330
- case "topLeft":
331
- newWidth = clampWidth(resizeStart.current.width - deltaX);
332
- newHeight = clampHeight(resizeStart.current.height - deltaY);
333
- newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
334
- newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
335
- break;
336
- case "top":
337
- newHeight = clampHeight(resizeStart.current.height - deltaY);
338
- newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
339
- break;
340
- case "topRight":
341
- newWidth = clampWidth(resizeStart.current.width + deltaX);
342
- newHeight = clampHeight(resizeStart.current.height - deltaY);
343
- newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
344
- break;
345
- case "right":
346
- newWidth = clampWidth(resizeStart.current.width + deltaX);
347
- break;
348
- case "bottomRight":
349
- newWidth = clampWidth(resizeStart.current.width + deltaX);
350
- newHeight = clampHeight(resizeStart.current.height + deltaY);
351
- break;
352
- case "bottom":
353
- newHeight = clampHeight(resizeStart.current.height + deltaY);
354
- break;
355
- case "bottomLeft":
356
- newWidth = clampWidth(resizeStart.current.width - deltaX);
357
- newHeight = clampHeight(resizeStart.current.height + deltaY);
358
- newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
359
- break;
360
- case "left":
361
- newWidth = clampWidth(resizeStart.current.width - deltaX);
362
- newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
363
- break;
586
+ handleResize(e.clientX, e.clientY);
587
+ }
588
+ };
589
+ const handleTouchMove = (e) => {
590
+ if (!e.touches[0]) {
591
+ return;
592
+ }
593
+ if (isDragging.current || isResizing.current) {
594
+ const touch = e.touches[0];
595
+ if (isDragging.current) {
596
+ const newPos = applyDragBounds(
597
+ touch.clientX - dragStart.current.x,
598
+ touch.clientY - dragStart.current.y
599
+ );
600
+ setPosition(newPos);
364
601
  }
365
- setSize({ width: newWidth, height: newHeight });
366
- if (newX !== resizeStart.current.posX || newY !== resizeStart.current.posY) {
367
- setPosition({ x: newX, y: newY });
602
+ if (isResizing.current) {
603
+ handleResize(touch.clientX, touch.clientY);
368
604
  }
605
+ e.preventDefault();
369
606
  }
370
607
  };
371
608
  const handleMouseUp = () => {
@@ -376,27 +613,29 @@ function useMantineWindow(props) {
376
613
  document.body.style.cursor = "";
377
614
  }
378
615
  };
616
+ const handleTouchEnd = () => {
617
+ if (isDragging.current || isResizing.current) {
618
+ isDragging.current = false;
619
+ isResizing.current = false;
620
+ document.body.style.userSelect = "";
621
+ document.body.style.cursor = "";
622
+ }
623
+ };
379
624
  document.addEventListener("mousemove", handleMouseMove);
380
625
  document.addEventListener("mouseup", handleMouseUp);
626
+ document.addEventListener("touchmove", handleTouchMove, { passive: false });
627
+ document.addEventListener("touchend", handleTouchEnd);
628
+ document.addEventListener("touchcancel", handleTouchEnd);
381
629
  return () => {
382
630
  document.removeEventListener("mousemove", handleMouseMove);
383
631
  document.removeEventListener("mouseup", handleMouseUp);
632
+ document.removeEventListener("touchmove", handleTouchMove);
633
+ document.removeEventListener("touchend", handleTouchEnd);
634
+ document.removeEventListener("touchcancel", handleTouchEnd);
384
635
  document.body.style.userSelect = "";
636
+ document.body.style.cursor = "";
385
637
  };
386
- }, [
387
- size.width,
388
- size.height,
389
- position.x,
390
- position.y,
391
- dragBounds,
392
- minWidth,
393
- minHeight,
394
- maxWidth,
395
- maxHeight,
396
- withinPortal,
397
- setPosition,
398
- setSize
399
- ]);
638
+ }, [applyDragBounds, handleResize, setPosition]);
400
639
  return {
401
640
  isCollapsed,
402
641
  setIsCollapsed,
@@ -407,14 +646,23 @@ function useMantineWindow(props) {
407
646
  size,
408
647
  windowRef,
409
648
  handleMouseDownDrag,
649
+ handleTouchStartDrag,
410
650
  handleMouseDownResizeTopLeft,
651
+ handleTouchStartResizeTopLeft,
411
652
  handleMouseDownResizeTop,
653
+ handleTouchStartResizeTop,
412
654
  handleMouseDownResizeTopRight,
655
+ handleTouchStartResizeTopRight,
413
656
  handleMouseDownResizeRight,
657
+ handleTouchStartResizeRight,
414
658
  handleMouseDownResizeBottomRight,
659
+ handleTouchStartResizeBottomRight,
415
660
  handleMouseDownResizeBottom,
661
+ handleTouchStartResizeBottom,
416
662
  handleMouseDownResizeBottomLeft,
663
+ handleTouchStartResizeBottomLeft,
417
664
  handleMouseDownResizeLeft,
665
+ handleTouchStartResizeLeft,
418
666
  handleClose,
419
667
  bringToFront
420
668
  };