react-resizable-panels 1.0.10 → 2.0.1

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.
@@ -200,6 +200,322 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
200
200
  PanelWithForwardedRef.displayName = "Panel";
201
201
  Panel.displayName = "forwardRef(Panel)";
202
202
 
203
+ let currentCursorStyle = null;
204
+ let styleElement = null;
205
+ function getCursorStyle(state, constraintFlags) {
206
+ if (constraintFlags) {
207
+ const horizontalMin = (constraintFlags & EXCEEDED_HORIZONTAL_MIN) !== 0;
208
+ const horizontalMax = (constraintFlags & EXCEEDED_HORIZONTAL_MAX) !== 0;
209
+ const verticalMin = (constraintFlags & EXCEEDED_VERTICAL_MIN) !== 0;
210
+ const verticalMax = (constraintFlags & EXCEEDED_VERTICAL_MAX) !== 0;
211
+ if (horizontalMin) {
212
+ if (verticalMin) {
213
+ return "se-resize";
214
+ } else if (verticalMax) {
215
+ return "ne-resize";
216
+ } else {
217
+ return "e-resize";
218
+ }
219
+ } else if (horizontalMax) {
220
+ if (verticalMin) {
221
+ return "sw-resize";
222
+ } else if (verticalMax) {
223
+ return "nw-resize";
224
+ } else {
225
+ return "w-resize";
226
+ }
227
+ } else if (verticalMin) {
228
+ return "s-resize";
229
+ } else if (verticalMax) {
230
+ return "n-resize";
231
+ }
232
+ }
233
+ switch (state) {
234
+ case "horizontal":
235
+ return "ew-resize";
236
+ case "intersection":
237
+ return "move";
238
+ case "vertical":
239
+ return "ns-resize";
240
+ }
241
+ }
242
+ function resetGlobalCursorStyle() {
243
+ if (styleElement !== null) {
244
+ document.head.removeChild(styleElement);
245
+ currentCursorStyle = null;
246
+ styleElement = null;
247
+ }
248
+ }
249
+ function setGlobalCursorStyle(state, constraintFlags) {
250
+ const style = getCursorStyle(state, constraintFlags);
251
+ if (currentCursorStyle === style) {
252
+ return;
253
+ }
254
+ currentCursorStyle = style;
255
+ if (styleElement === null) {
256
+ styleElement = document.createElement("style");
257
+ document.head.appendChild(styleElement);
258
+ }
259
+ styleElement.innerHTML = `*{cursor: ${style}!important;}`;
260
+ }
261
+
262
+ function isKeyDown(event) {
263
+ return event.type === "keydown";
264
+ }
265
+ function isMouseEvent(event) {
266
+ return event.type.startsWith("mouse");
267
+ }
268
+ function isTouchEvent(event) {
269
+ return event.type.startsWith("touch");
270
+ }
271
+
272
+ function getResizeEventCoordinates(event) {
273
+ if (isMouseEvent(event)) {
274
+ return {
275
+ x: event.pageX,
276
+ y: event.pageY
277
+ };
278
+ } else if (isTouchEvent(event)) {
279
+ const touch = event.touches[0];
280
+ if (touch && touch.pageX && touch.pageY) {
281
+ return {
282
+ x: touch.pageX,
283
+ y: touch.pageY
284
+ };
285
+ }
286
+ }
287
+ return {
288
+ x: Infinity,
289
+ y: Infinity
290
+ };
291
+ }
292
+
293
+ function getInputType() {
294
+ if (typeof matchMedia === "function") {
295
+ return matchMedia("(pointer:coarse)").matches ? "coarse" : "fine";
296
+ }
297
+ }
298
+
299
+ const EXCEEDED_HORIZONTAL_MIN = 0b0001;
300
+ const EXCEEDED_HORIZONTAL_MAX = 0b0010;
301
+ const EXCEEDED_VERTICAL_MIN = 0b0100;
302
+ const EXCEEDED_VERTICAL_MAX = 0b1000;
303
+ const isCoarsePointer = getInputType() === "coarse";
304
+ let intersectingHandles = [];
305
+ let isPointerDown = false;
306
+ let ownerDocumentCounts = new Map();
307
+ let panelConstraintFlags = new Map();
308
+ const registeredResizeHandlers = new Set();
309
+ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins, setResizeHandlerState) {
310
+ var _ownerDocumentCounts$;
311
+ const {
312
+ ownerDocument
313
+ } = element;
314
+ const data = {
315
+ direction,
316
+ element,
317
+ hitAreaMargins,
318
+ setResizeHandlerState
319
+ };
320
+ const count = (_ownerDocumentCounts$ = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$ !== void 0 ? _ownerDocumentCounts$ : 0;
321
+ ownerDocumentCounts.set(ownerDocument, count + 1);
322
+ registeredResizeHandlers.add(data);
323
+ updateListeners();
324
+ return function unregisterResizeHandle() {
325
+ var _ownerDocumentCounts$2;
326
+ panelConstraintFlags.delete(resizeHandleId);
327
+ registeredResizeHandlers.delete(data);
328
+ const count = (_ownerDocumentCounts$2 = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$2 !== void 0 ? _ownerDocumentCounts$2 : 1;
329
+ ownerDocumentCounts.set(ownerDocument, count - 1);
330
+ updateListeners();
331
+ if (count === 1) {
332
+ ownerDocumentCounts.delete(ownerDocument);
333
+ }
334
+ };
335
+ }
336
+ function handlePointerDown(event) {
337
+ const {
338
+ x,
339
+ y
340
+ } = getResizeEventCoordinates(event);
341
+ isPointerDown = true;
342
+ recalculateIntersectingHandles({
343
+ x,
344
+ y
345
+ });
346
+ updateListeners();
347
+ if (intersectingHandles.length > 0) {
348
+ updateResizeHandlerStates("down", event);
349
+ event.preventDefault();
350
+ }
351
+ }
352
+ function handlePointerMove(event) {
353
+ const {
354
+ x,
355
+ y
356
+ } = getResizeEventCoordinates(event);
357
+ if (isPointerDown) {
358
+ intersectingHandles.forEach(data => {
359
+ const {
360
+ setResizeHandlerState
361
+ } = data;
362
+ setResizeHandlerState("move", "drag", event);
363
+ });
364
+
365
+ // Update cursor based on return value(s) from active handles
366
+ updateCursor();
367
+ } else {
368
+ recalculateIntersectingHandles({
369
+ x,
370
+ y
371
+ });
372
+ updateResizeHandlerStates("move", event);
373
+ updateCursor();
374
+ }
375
+ if (intersectingHandles.length > 0) {
376
+ event.preventDefault();
377
+ }
378
+ }
379
+ function handlePointerUp(event) {
380
+ const {
381
+ x,
382
+ y
383
+ } = getResizeEventCoordinates(event);
384
+ panelConstraintFlags.clear();
385
+ isPointerDown = false;
386
+ if (intersectingHandles.length > 0) {
387
+ event.preventDefault();
388
+ }
389
+ recalculateIntersectingHandles({
390
+ x,
391
+ y
392
+ });
393
+ updateResizeHandlerStates("up", event);
394
+ updateCursor();
395
+ updateListeners();
396
+ }
397
+ function recalculateIntersectingHandles({
398
+ x,
399
+ y
400
+ }) {
401
+ intersectingHandles.splice(0);
402
+ registeredResizeHandlers.forEach(data => {
403
+ const {
404
+ element,
405
+ hitAreaMargins
406
+ } = data;
407
+ const {
408
+ bottom,
409
+ left,
410
+ right,
411
+ top
412
+ } = element.getBoundingClientRect();
413
+ const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
414
+ const intersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
415
+ if (intersects) {
416
+ intersectingHandles.push(data);
417
+ }
418
+ });
419
+ }
420
+ function reportConstraintsViolation(resizeHandleId, flag) {
421
+ panelConstraintFlags.set(resizeHandleId, flag);
422
+ }
423
+ function updateCursor() {
424
+ let intersectsHorizontal = false;
425
+ let intersectsVertical = false;
426
+ intersectingHandles.forEach(data => {
427
+ const {
428
+ direction
429
+ } = data;
430
+ if (direction === "horizontal") {
431
+ intersectsHorizontal = true;
432
+ } else {
433
+ intersectsVertical = true;
434
+ }
435
+ });
436
+ let constraintFlags = 0;
437
+ panelConstraintFlags.forEach(flag => {
438
+ constraintFlags |= flag;
439
+ });
440
+ if (intersectsHorizontal && intersectsVertical) {
441
+ setGlobalCursorStyle("intersection", constraintFlags);
442
+ } else if (intersectsHorizontal) {
443
+ setGlobalCursorStyle("horizontal", constraintFlags);
444
+ } else if (intersectsVertical) {
445
+ setGlobalCursorStyle("vertical", constraintFlags);
446
+ } else {
447
+ resetGlobalCursorStyle();
448
+ }
449
+ }
450
+ function updateListeners() {
451
+ ownerDocumentCounts.forEach((_, ownerDocument) => {
452
+ const {
453
+ body
454
+ } = ownerDocument;
455
+ body.removeEventListener("contextmenu", handlePointerUp);
456
+ body.removeEventListener("mousedown", handlePointerDown);
457
+ body.removeEventListener("mouseleave", handlePointerMove);
458
+ body.removeEventListener("mousemove", handlePointerMove);
459
+ body.removeEventListener("touchmove", handlePointerMove);
460
+ body.removeEventListener("touchstart", handlePointerDown);
461
+ });
462
+ window.removeEventListener("mouseup", handlePointerUp);
463
+ window.removeEventListener("touchcancel", handlePointerUp);
464
+ window.removeEventListener("touchend", handlePointerUp);
465
+ if (registerResizeHandle.length > 0) {
466
+ if (isPointerDown) {
467
+ if (intersectingHandles.length > 0) {
468
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
469
+ const {
470
+ body
471
+ } = ownerDocument;
472
+ if (count > 0) {
473
+ body.addEventListener("contextmenu", handlePointerUp);
474
+ body.addEventListener("mouseleave", handlePointerMove);
475
+ body.addEventListener("mousemove", handlePointerMove);
476
+ body.addEventListener("touchmove", handlePointerMove, {
477
+ passive: false
478
+ });
479
+ }
480
+ });
481
+ }
482
+ window.addEventListener("mouseup", handlePointerUp);
483
+ window.addEventListener("touchcancel", handlePointerUp);
484
+ window.addEventListener("touchend", handlePointerUp);
485
+ } else {
486
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
487
+ const {
488
+ body
489
+ } = ownerDocument;
490
+ if (count > 0) {
491
+ body.addEventListener("mousedown", handlePointerDown);
492
+ body.addEventListener("mousemove", handlePointerMove);
493
+ body.addEventListener("touchmove", handlePointerMove, {
494
+ passive: false
495
+ });
496
+ body.addEventListener("touchstart", handlePointerDown);
497
+ }
498
+ });
499
+ }
500
+ }
501
+ }
502
+ function updateResizeHandlerStates(action, event) {
503
+ registeredResizeHandlers.forEach(data => {
504
+ const {
505
+ setResizeHandlerState
506
+ } = data;
507
+ if (intersectingHandles.includes(data)) {
508
+ if (isPointerDown) {
509
+ setResizeHandlerState(action, "drag", event);
510
+ } else {
511
+ setResizeHandlerState(action, "hover", event);
512
+ }
513
+ } else {
514
+ setResizeHandlerState(action, "inactive", event);
515
+ }
516
+ });
517
+ }
518
+
203
519
  function assert(expectedCondition, message = "Assertion failed!") {
204
520
  if (!expectedCondition) {
205
521
  console.error(message);
@@ -705,27 +1021,13 @@ function areEqual(arrayA, arrayB) {
705
1021
  return true;
706
1022
  }
707
1023
 
708
- function isKeyDown(event) {
709
- return event.type === "keydown";
710
- }
711
- function isMouseEvent(event) {
712
- return event.type.startsWith("mouse");
713
- }
714
- function isTouchEvent(event) {
715
- return event.type.startsWith("touch");
716
- }
717
-
718
1024
  function getResizeEventCursorPosition(direction, event) {
719
1025
  const isHorizontal = direction === "horizontal";
720
- if (isMouseEvent(event)) {
721
- return isHorizontal ? event.clientX : event.clientY;
722
- } else if (isTouchEvent(event)) {
723
- const firstTouch = event.touches[0];
724
- assert(firstTouch);
725
- return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
726
- } else {
727
- throw Error(`Unsupported event type "${event.type}"`);
728
- }
1026
+ const {
1027
+ x,
1028
+ y
1029
+ } = getResizeEventCoordinates(event);
1030
+ return isHorizontal ? x : y;
729
1031
  }
730
1032
 
731
1033
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
@@ -915,44 +1217,6 @@ function computePanelFlexBoxStyle({
915
1217
  };
916
1218
  }
917
1219
 
918
- let currentState = null;
919
- let element = null;
920
- function getCursorStyle(state) {
921
- switch (state) {
922
- case "horizontal":
923
- return "ew-resize";
924
- case "horizontal-max":
925
- return "w-resize";
926
- case "horizontal-min":
927
- return "e-resize";
928
- case "vertical":
929
- return "ns-resize";
930
- case "vertical-max":
931
- return "n-resize";
932
- case "vertical-min":
933
- return "s-resize";
934
- }
935
- }
936
- function resetGlobalCursorStyle() {
937
- if (element !== null) {
938
- document.head.removeChild(element);
939
- currentState = null;
940
- element = null;
941
- }
942
- }
943
- function setGlobalCursorStyle(state) {
944
- if (currentState === state) {
945
- return;
946
- }
947
- currentState = state;
948
- const style = getCursorStyle(state);
949
- if (element === null) {
950
- element = document.createElement("style");
951
- document.head.appendChild(element);
952
- }
953
- element.innerHTML = `*{cursor: ${style}!important;}`;
954
- }
955
-
956
1220
  function debounce(callback, durationMs = 10) {
957
1221
  let timeoutId = null;
958
1222
  let callable = (...args) => {
@@ -1498,18 +1762,15 @@ function PanelGroupWithForwardedRef({
1498
1762
  if (prevDeltaRef.current != delta) {
1499
1763
  prevDeltaRef.current = delta;
1500
1764
  if (!layoutChanged) {
1501
- // If the pointer has moved too far to resize the panel any further,
1502
- // update the cursor style for a visual clue.
1765
+ // If the pointer has moved too far to resize the panel any further, note this so we can update the cursor.
1503
1766
  // This mimics VS Code behavior.
1504
-
1505
1767
  if (isHorizontal) {
1506
- setGlobalCursorStyle(delta < 0 ? "horizontal-min" : "horizontal-max");
1768
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_HORIZONTAL_MIN : EXCEEDED_HORIZONTAL_MAX);
1507
1769
  } else {
1508
- setGlobalCursorStyle(delta < 0 ? "vertical-min" : "vertical-max");
1770
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_VERTICAL_MIN : EXCEEDED_VERTICAL_MAX);
1509
1771
  }
1510
1772
  } else {
1511
- // Reset the cursor style to the the normal resize cursor.
1512
- setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
1773
+ reportConstraintsViolation(dragHandleId, 0);
1513
1774
  }
1514
1775
  }
1515
1776
  }
@@ -1607,7 +1868,6 @@ function PanelGroupWithForwardedRef({
1607
1868
  });
1608
1869
  }, []);
1609
1870
  const stopDragging = useCallback(() => {
1610
- resetGlobalCursorStyle();
1611
1871
  setDragState(null);
1612
1872
  }, []);
1613
1873
  const unregisterPanel = useCallback(panelData => {
@@ -1748,6 +2008,7 @@ function PanelResizeHandle({
1748
2008
  children = null,
1749
2009
  className: classNameFromProps = "",
1750
2010
  disabled = false,
2011
+ hitAreaMargins,
1751
2012
  id: idFromProps,
1752
2013
  onDragging,
1753
2014
  style: styleFromProps = {},
@@ -1770,67 +2031,60 @@ function PanelResizeHandle({
1770
2031
  }
1771
2032
  const {
1772
2033
  direction,
1773
- dragState,
1774
2034
  groupId,
1775
- registerResizeHandle,
2035
+ registerResizeHandle: registerResizeHandleWithParentGroup,
1776
2036
  startDragging,
1777
2037
  stopDragging,
1778
2038
  panelGroupElement
1779
2039
  } = panelGroupContext;
1780
2040
  const resizeHandleId = useUniqueId(idFromProps);
1781
- const isDragging = (dragState === null || dragState === void 0 ? void 0 : dragState.dragHandleId) === resizeHandleId;
2041
+ const [state, setState] = useState("inactive");
1782
2042
  const [isFocused, setIsFocused] = useState(false);
1783
2043
  const [resizeHandler, setResizeHandler] = useState(null);
1784
- const stopDraggingAndBlur = useCallback(() => {
1785
- // Clicking on the drag handle shouldn't leave it focused;
1786
- // That would cause the PanelGroup to think it was still active.
1787
- const element = elementRef.current;
1788
- assert(element);
1789
- element.blur();
1790
- stopDragging();
1791
- const {
1792
- onDragging
1793
- } = callbacksRef.current;
1794
- if (onDragging) {
1795
- onDragging(false);
1796
- }
1797
- }, [stopDragging]);
1798
2044
  useEffect(() => {
1799
2045
  if (disabled) {
1800
2046
  setResizeHandler(null);
1801
2047
  } else {
1802
- const resizeHandler = registerResizeHandle(resizeHandleId);
2048
+ const resizeHandler = registerResizeHandleWithParentGroup(resizeHandleId);
1803
2049
  setResizeHandler(() => resizeHandler);
1804
2050
  }
1805
- }, [disabled, resizeHandleId, registerResizeHandle]);
2051
+ }, [disabled, resizeHandleId, registerResizeHandleWithParentGroup]);
1806
2052
  useEffect(() => {
1807
- if (disabled || resizeHandler == null || !isDragging) {
2053
+ var _hitAreaMargins$coars, _hitAreaMargins$fine;
2054
+ if (disabled || resizeHandler == null) {
1808
2055
  return;
1809
2056
  }
1810
- const onMove = event => {
1811
- resizeHandler(event);
1812
- };
1813
- const onMouseLeave = event => {
1814
- resizeHandler(event);
1815
- };
1816
2057
  const element = elementRef.current;
1817
2058
  assert(element);
1818
- const targetDocument = element.ownerDocument;
1819
- targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1820
- targetDocument.body.addEventListener("mousemove", onMove);
1821
- targetDocument.body.addEventListener("touchmove", onMove);
1822
- targetDocument.body.addEventListener("mouseleave", onMouseLeave);
1823
- window.addEventListener("mouseup", stopDraggingAndBlur);
1824
- window.addEventListener("touchend", stopDraggingAndBlur);
1825
- return () => {
1826
- targetDocument.body.removeEventListener("contextmenu", stopDraggingAndBlur);
1827
- targetDocument.body.removeEventListener("mousemove", onMove);
1828
- targetDocument.body.removeEventListener("touchmove", onMove);
1829
- targetDocument.body.removeEventListener("mouseleave", onMouseLeave);
1830
- window.removeEventListener("mouseup", stopDraggingAndBlur);
1831
- window.removeEventListener("touchend", stopDraggingAndBlur);
2059
+ const setResizeHandlerState = (action, state, event) => {
2060
+ setState(state);
2061
+ switch (action) {
2062
+ case "down":
2063
+ {
2064
+ startDragging(resizeHandleId, event);
2065
+ break;
2066
+ }
2067
+ case "up":
2068
+ {
2069
+ stopDragging();
2070
+ break;
2071
+ }
2072
+ }
2073
+ switch (state) {
2074
+ case "drag":
2075
+ {
2076
+ resizeHandler(event);
2077
+ break;
2078
+ }
2079
+ }
1832
2080
  };
1833
- }, [direction, disabled, isDragging, resizeHandler, stopDraggingAndBlur]);
2081
+ return registerResizeHandle(resizeHandleId, element, direction, {
2082
+ // Coarse inputs (e.g. finger/touch)
2083
+ coarse: (_hitAreaMargins$coars = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.coarse) !== null && _hitAreaMargins$coars !== void 0 ? _hitAreaMargins$coars : 15,
2084
+ // Fine inputs (e.g. mouse)
2085
+ fine: (_hitAreaMargins$fine = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.fine) !== null && _hitAreaMargins$fine !== void 0 ? _hitAreaMargins$fine : 5
2086
+ }, setResizeHandlerState);
2087
+ }, [direction, disabled, hitAreaMargins, registerResizeHandleWithParentGroup, resizeHandleId, resizeHandler, startDragging, stopDragging]);
1834
2088
  useWindowSplitterResizeHandlerBehavior({
1835
2089
  disabled,
1836
2090
  handleId: resizeHandleId,
@@ -1838,7 +2092,6 @@ function PanelResizeHandle({
1838
2092
  panelGroupElement
1839
2093
  });
1840
2094
  const style = {
1841
- cursor: getCursorStyle(direction),
1842
2095
  touchAction: "none",
1843
2096
  userSelect: "none"
1844
2097
  };
@@ -1848,31 +2101,6 @@ function PanelResizeHandle({
1848
2101
  className: classNameFromProps,
1849
2102
  onBlur: () => setIsFocused(false),
1850
2103
  onFocus: () => setIsFocused(true),
1851
- onMouseDown: event => {
1852
- startDragging(resizeHandleId, event.nativeEvent);
1853
- const callbacks = callbacksRef.current;
1854
- assert(callbacks);
1855
- const {
1856
- onDragging
1857
- } = callbacks;
1858
- if (onDragging) {
1859
- onDragging(true);
1860
- }
1861
- },
1862
- onMouseUp: stopDraggingAndBlur,
1863
- onTouchCancel: stopDraggingAndBlur,
1864
- onTouchEnd: stopDraggingAndBlur,
1865
- onTouchStart: event => {
1866
- startDragging(resizeHandleId, event.nativeEvent);
1867
- const callbacks = callbacksRef.current;
1868
- assert(callbacks);
1869
- const {
1870
- onDragging
1871
- } = callbacks;
1872
- if (onDragging) {
1873
- onDragging(true);
1874
- }
1875
- },
1876
2104
  ref: elementRef,
1877
2105
  role: "separator",
1878
2106
  style: {
@@ -1884,7 +2112,8 @@ function PanelResizeHandle({
1884
2112
  "data-panel-group-direction": direction,
1885
2113
  "data-panel-group-id": groupId,
1886
2114
  "data-resize-handle": "",
1887
- "data-resize-handle-active": isDragging ? "pointer" : isFocused ? "keyboard" : undefined,
2115
+ "data-resize-handle-active": state === "drag" ? "pointer" : isFocused ? "keyboard" : undefined,
2116
+ "data-resize-handle-state": state,
1888
2117
  "data-panel-resize-handle-enabled": !disabled,
1889
2118
  "data-panel-resize-handle-id": resizeHandleId
1890
2119
  });