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.
@@ -150,6 +150,322 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
150
150
  PanelWithForwardedRef.displayName = "Panel";
151
151
  Panel.displayName = "forwardRef(Panel)";
152
152
 
153
+ let currentCursorStyle = null;
154
+ let styleElement = null;
155
+ function getCursorStyle(state, constraintFlags) {
156
+ if (constraintFlags) {
157
+ const horizontalMin = (constraintFlags & EXCEEDED_HORIZONTAL_MIN) !== 0;
158
+ const horizontalMax = (constraintFlags & EXCEEDED_HORIZONTAL_MAX) !== 0;
159
+ const verticalMin = (constraintFlags & EXCEEDED_VERTICAL_MIN) !== 0;
160
+ const verticalMax = (constraintFlags & EXCEEDED_VERTICAL_MAX) !== 0;
161
+ if (horizontalMin) {
162
+ if (verticalMin) {
163
+ return "se-resize";
164
+ } else if (verticalMax) {
165
+ return "ne-resize";
166
+ } else {
167
+ return "e-resize";
168
+ }
169
+ } else if (horizontalMax) {
170
+ if (verticalMin) {
171
+ return "sw-resize";
172
+ } else if (verticalMax) {
173
+ return "nw-resize";
174
+ } else {
175
+ return "w-resize";
176
+ }
177
+ } else if (verticalMin) {
178
+ return "s-resize";
179
+ } else if (verticalMax) {
180
+ return "n-resize";
181
+ }
182
+ }
183
+ switch (state) {
184
+ case "horizontal":
185
+ return "ew-resize";
186
+ case "intersection":
187
+ return "move";
188
+ case "vertical":
189
+ return "ns-resize";
190
+ }
191
+ }
192
+ function resetGlobalCursorStyle() {
193
+ if (styleElement !== null) {
194
+ document.head.removeChild(styleElement);
195
+ currentCursorStyle = null;
196
+ styleElement = null;
197
+ }
198
+ }
199
+ function setGlobalCursorStyle(state, constraintFlags) {
200
+ const style = getCursorStyle(state, constraintFlags);
201
+ if (currentCursorStyle === style) {
202
+ return;
203
+ }
204
+ currentCursorStyle = style;
205
+ if (styleElement === null) {
206
+ styleElement = document.createElement("style");
207
+ document.head.appendChild(styleElement);
208
+ }
209
+ styleElement.innerHTML = `*{cursor: ${style}!important;}`;
210
+ }
211
+
212
+ function isKeyDown(event) {
213
+ return event.type === "keydown";
214
+ }
215
+ function isMouseEvent(event) {
216
+ return event.type.startsWith("mouse");
217
+ }
218
+ function isTouchEvent(event) {
219
+ return event.type.startsWith("touch");
220
+ }
221
+
222
+ function getResizeEventCoordinates(event) {
223
+ if (isMouseEvent(event)) {
224
+ return {
225
+ x: event.pageX,
226
+ y: event.pageY
227
+ };
228
+ } else if (isTouchEvent(event)) {
229
+ const touch = event.touches[0];
230
+ if (touch && touch.pageX && touch.pageY) {
231
+ return {
232
+ x: touch.pageX,
233
+ y: touch.pageY
234
+ };
235
+ }
236
+ }
237
+ return {
238
+ x: Infinity,
239
+ y: Infinity
240
+ };
241
+ }
242
+
243
+ function getInputType() {
244
+ if (typeof matchMedia === "function") {
245
+ return matchMedia("(pointer:coarse)").matches ? "coarse" : "fine";
246
+ }
247
+ }
248
+
249
+ const EXCEEDED_HORIZONTAL_MIN = 0b0001;
250
+ const EXCEEDED_HORIZONTAL_MAX = 0b0010;
251
+ const EXCEEDED_VERTICAL_MIN = 0b0100;
252
+ const EXCEEDED_VERTICAL_MAX = 0b1000;
253
+ const isCoarsePointer = getInputType() === "coarse";
254
+ let intersectingHandles = [];
255
+ let isPointerDown = false;
256
+ let ownerDocumentCounts = new Map();
257
+ let panelConstraintFlags = new Map();
258
+ const registeredResizeHandlers = new Set();
259
+ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins, setResizeHandlerState) {
260
+ var _ownerDocumentCounts$;
261
+ const {
262
+ ownerDocument
263
+ } = element;
264
+ const data = {
265
+ direction,
266
+ element,
267
+ hitAreaMargins,
268
+ setResizeHandlerState
269
+ };
270
+ const count = (_ownerDocumentCounts$ = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$ !== void 0 ? _ownerDocumentCounts$ : 0;
271
+ ownerDocumentCounts.set(ownerDocument, count + 1);
272
+ registeredResizeHandlers.add(data);
273
+ updateListeners();
274
+ return function unregisterResizeHandle() {
275
+ var _ownerDocumentCounts$2;
276
+ panelConstraintFlags.delete(resizeHandleId);
277
+ registeredResizeHandlers.delete(data);
278
+ const count = (_ownerDocumentCounts$2 = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$2 !== void 0 ? _ownerDocumentCounts$2 : 1;
279
+ ownerDocumentCounts.set(ownerDocument, count - 1);
280
+ updateListeners();
281
+ if (count === 1) {
282
+ ownerDocumentCounts.delete(ownerDocument);
283
+ }
284
+ };
285
+ }
286
+ function handlePointerDown(event) {
287
+ const {
288
+ x,
289
+ y
290
+ } = getResizeEventCoordinates(event);
291
+ isPointerDown = true;
292
+ recalculateIntersectingHandles({
293
+ x,
294
+ y
295
+ });
296
+ updateListeners();
297
+ if (intersectingHandles.length > 0) {
298
+ updateResizeHandlerStates("down", event);
299
+ event.preventDefault();
300
+ }
301
+ }
302
+ function handlePointerMove(event) {
303
+ const {
304
+ x,
305
+ y
306
+ } = getResizeEventCoordinates(event);
307
+ if (isPointerDown) {
308
+ intersectingHandles.forEach(data => {
309
+ const {
310
+ setResizeHandlerState
311
+ } = data;
312
+ setResizeHandlerState("move", "drag", event);
313
+ });
314
+
315
+ // Update cursor based on return value(s) from active handles
316
+ updateCursor();
317
+ } else {
318
+ recalculateIntersectingHandles({
319
+ x,
320
+ y
321
+ });
322
+ updateResizeHandlerStates("move", event);
323
+ updateCursor();
324
+ }
325
+ if (intersectingHandles.length > 0) {
326
+ event.preventDefault();
327
+ }
328
+ }
329
+ function handlePointerUp(event) {
330
+ const {
331
+ x,
332
+ y
333
+ } = getResizeEventCoordinates(event);
334
+ panelConstraintFlags.clear();
335
+ isPointerDown = false;
336
+ if (intersectingHandles.length > 0) {
337
+ event.preventDefault();
338
+ }
339
+ recalculateIntersectingHandles({
340
+ x,
341
+ y
342
+ });
343
+ updateResizeHandlerStates("up", event);
344
+ updateCursor();
345
+ updateListeners();
346
+ }
347
+ function recalculateIntersectingHandles({
348
+ x,
349
+ y
350
+ }) {
351
+ intersectingHandles.splice(0);
352
+ registeredResizeHandlers.forEach(data => {
353
+ const {
354
+ element,
355
+ hitAreaMargins
356
+ } = data;
357
+ const {
358
+ bottom,
359
+ left,
360
+ right,
361
+ top
362
+ } = element.getBoundingClientRect();
363
+ const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
364
+ const intersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
365
+ if (intersects) {
366
+ intersectingHandles.push(data);
367
+ }
368
+ });
369
+ }
370
+ function reportConstraintsViolation(resizeHandleId, flag) {
371
+ panelConstraintFlags.set(resizeHandleId, flag);
372
+ }
373
+ function updateCursor() {
374
+ let intersectsHorizontal = false;
375
+ let intersectsVertical = false;
376
+ intersectingHandles.forEach(data => {
377
+ const {
378
+ direction
379
+ } = data;
380
+ if (direction === "horizontal") {
381
+ intersectsHorizontal = true;
382
+ } else {
383
+ intersectsVertical = true;
384
+ }
385
+ });
386
+ let constraintFlags = 0;
387
+ panelConstraintFlags.forEach(flag => {
388
+ constraintFlags |= flag;
389
+ });
390
+ if (intersectsHorizontal && intersectsVertical) {
391
+ setGlobalCursorStyle("intersection", constraintFlags);
392
+ } else if (intersectsHorizontal) {
393
+ setGlobalCursorStyle("horizontal", constraintFlags);
394
+ } else if (intersectsVertical) {
395
+ setGlobalCursorStyle("vertical", constraintFlags);
396
+ } else {
397
+ resetGlobalCursorStyle();
398
+ }
399
+ }
400
+ function updateListeners() {
401
+ ownerDocumentCounts.forEach((_, ownerDocument) => {
402
+ const {
403
+ body
404
+ } = ownerDocument;
405
+ body.removeEventListener("contextmenu", handlePointerUp);
406
+ body.removeEventListener("mousedown", handlePointerDown);
407
+ body.removeEventListener("mouseleave", handlePointerMove);
408
+ body.removeEventListener("mousemove", handlePointerMove);
409
+ body.removeEventListener("touchmove", handlePointerMove);
410
+ body.removeEventListener("touchstart", handlePointerDown);
411
+ });
412
+ window.removeEventListener("mouseup", handlePointerUp);
413
+ window.removeEventListener("touchcancel", handlePointerUp);
414
+ window.removeEventListener("touchend", handlePointerUp);
415
+ if (registerResizeHandle.length > 0) {
416
+ if (isPointerDown) {
417
+ if (intersectingHandles.length > 0) {
418
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
419
+ const {
420
+ body
421
+ } = ownerDocument;
422
+ if (count > 0) {
423
+ body.addEventListener("contextmenu", handlePointerUp);
424
+ body.addEventListener("mouseleave", handlePointerMove);
425
+ body.addEventListener("mousemove", handlePointerMove);
426
+ body.addEventListener("touchmove", handlePointerMove, {
427
+ passive: false
428
+ });
429
+ }
430
+ });
431
+ }
432
+ window.addEventListener("mouseup", handlePointerUp);
433
+ window.addEventListener("touchcancel", handlePointerUp);
434
+ window.addEventListener("touchend", handlePointerUp);
435
+ } else {
436
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
437
+ const {
438
+ body
439
+ } = ownerDocument;
440
+ if (count > 0) {
441
+ body.addEventListener("mousedown", handlePointerDown);
442
+ body.addEventListener("mousemove", handlePointerMove);
443
+ body.addEventListener("touchmove", handlePointerMove, {
444
+ passive: false
445
+ });
446
+ body.addEventListener("touchstart", handlePointerDown);
447
+ }
448
+ });
449
+ }
450
+ }
451
+ }
452
+ function updateResizeHandlerStates(action, event) {
453
+ registeredResizeHandlers.forEach(data => {
454
+ const {
455
+ setResizeHandlerState
456
+ } = data;
457
+ if (intersectingHandles.includes(data)) {
458
+ if (isPointerDown) {
459
+ setResizeHandlerState(action, "drag", event);
460
+ } else {
461
+ setResizeHandlerState(action, "hover", event);
462
+ }
463
+ } else {
464
+ setResizeHandlerState(action, "inactive", event);
465
+ }
466
+ });
467
+ }
468
+
153
469
  function assert(expectedCondition, message = "Assertion failed!") {
154
470
  if (!expectedCondition) {
155
471
  console.error(message);
@@ -582,27 +898,13 @@ function areEqual(arrayA, arrayB) {
582
898
  return true;
583
899
  }
584
900
 
585
- function isKeyDown(event) {
586
- return event.type === "keydown";
587
- }
588
- function isMouseEvent(event) {
589
- return event.type.startsWith("mouse");
590
- }
591
- function isTouchEvent(event) {
592
- return event.type.startsWith("touch");
593
- }
594
-
595
901
  function getResizeEventCursorPosition(direction, event) {
596
902
  const isHorizontal = direction === "horizontal";
597
- if (isMouseEvent(event)) {
598
- return isHorizontal ? event.clientX : event.clientY;
599
- } else if (isTouchEvent(event)) {
600
- const firstTouch = event.touches[0];
601
- assert(firstTouch);
602
- return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
603
- } else {
604
- throw Error(`Unsupported event type "${event.type}"`);
605
- }
903
+ const {
904
+ x,
905
+ y
906
+ } = getResizeEventCoordinates(event);
907
+ return isHorizontal ? x : y;
606
908
  }
607
909
 
608
910
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
@@ -751,44 +1053,6 @@ function computePanelFlexBoxStyle({
751
1053
  };
752
1054
  }
753
1055
 
754
- let currentState = null;
755
- let element = null;
756
- function getCursorStyle(state) {
757
- switch (state) {
758
- case "horizontal":
759
- return "ew-resize";
760
- case "horizontal-max":
761
- return "w-resize";
762
- case "horizontal-min":
763
- return "e-resize";
764
- case "vertical":
765
- return "ns-resize";
766
- case "vertical-max":
767
- return "n-resize";
768
- case "vertical-min":
769
- return "s-resize";
770
- }
771
- }
772
- function resetGlobalCursorStyle() {
773
- if (element !== null) {
774
- document.head.removeChild(element);
775
- currentState = null;
776
- element = null;
777
- }
778
- }
779
- function setGlobalCursorStyle(state) {
780
- if (currentState === state) {
781
- return;
782
- }
783
- currentState = state;
784
- const style = getCursorStyle(state);
785
- if (element === null) {
786
- element = document.createElement("style");
787
- document.head.appendChild(element);
788
- }
789
- element.innerHTML = `*{cursor: ${style}!important;}`;
790
- }
791
-
792
1056
  function debounce(callback, durationMs = 10) {
793
1057
  let timeoutId = null;
794
1058
  let callable = (...args) => {
@@ -1362,18 +1626,15 @@ function PanelGroupWithForwardedRef({
1362
1626
  if (prevDeltaRef.current != delta) {
1363
1627
  prevDeltaRef.current = delta;
1364
1628
  if (!layoutChanged) {
1365
- // If the pointer has moved too far to resize the panel any further,
1366
- // update the cursor style for a visual clue.
1629
+ // If the pointer has moved too far to resize the panel any further, note this so we can update the cursor.
1367
1630
  // This mimics VS Code behavior.
1368
-
1369
1631
  if (isHorizontal) {
1370
- setGlobalCursorStyle(delta < 0 ? "horizontal-min" : "horizontal-max");
1632
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_HORIZONTAL_MIN : EXCEEDED_HORIZONTAL_MAX);
1371
1633
  } else {
1372
- setGlobalCursorStyle(delta < 0 ? "vertical-min" : "vertical-max");
1634
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_VERTICAL_MIN : EXCEEDED_VERTICAL_MAX);
1373
1635
  }
1374
1636
  } else {
1375
- // Reset the cursor style to the the normal resize cursor.
1376
- setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
1637
+ reportConstraintsViolation(dragHandleId, 0);
1377
1638
  }
1378
1639
  }
1379
1640
  }
@@ -1471,7 +1732,6 @@ function PanelGroupWithForwardedRef({
1471
1732
  });
1472
1733
  }, []);
1473
1734
  const stopDragging = useCallback(() => {
1474
- resetGlobalCursorStyle();
1475
1735
  setDragState(null);
1476
1736
  }, []);
1477
1737
  const unregisterPanel = useCallback(panelData => {
@@ -1612,6 +1872,7 @@ function PanelResizeHandle({
1612
1872
  children = null,
1613
1873
  className: classNameFromProps = "",
1614
1874
  disabled = false,
1875
+ hitAreaMargins,
1615
1876
  id: idFromProps,
1616
1877
  onDragging,
1617
1878
  style: styleFromProps = {},
@@ -1634,67 +1895,60 @@ function PanelResizeHandle({
1634
1895
  }
1635
1896
  const {
1636
1897
  direction,
1637
- dragState,
1638
1898
  groupId,
1639
- registerResizeHandle,
1899
+ registerResizeHandle: registerResizeHandleWithParentGroup,
1640
1900
  startDragging,
1641
1901
  stopDragging,
1642
1902
  panelGroupElement
1643
1903
  } = panelGroupContext;
1644
1904
  const resizeHandleId = useUniqueId(idFromProps);
1645
- const isDragging = (dragState === null || dragState === void 0 ? void 0 : dragState.dragHandleId) === resizeHandleId;
1905
+ const [state, setState] = useState("inactive");
1646
1906
  const [isFocused, setIsFocused] = useState(false);
1647
1907
  const [resizeHandler, setResizeHandler] = useState(null);
1648
- const stopDraggingAndBlur = useCallback(() => {
1649
- // Clicking on the drag handle shouldn't leave it focused;
1650
- // That would cause the PanelGroup to think it was still active.
1651
- const element = elementRef.current;
1652
- assert(element);
1653
- element.blur();
1654
- stopDragging();
1655
- const {
1656
- onDragging
1657
- } = callbacksRef.current;
1658
- if (onDragging) {
1659
- onDragging(false);
1660
- }
1661
- }, [stopDragging]);
1662
1908
  useEffect(() => {
1663
1909
  if (disabled) {
1664
1910
  setResizeHandler(null);
1665
1911
  } else {
1666
- const resizeHandler = registerResizeHandle(resizeHandleId);
1912
+ const resizeHandler = registerResizeHandleWithParentGroup(resizeHandleId);
1667
1913
  setResizeHandler(() => resizeHandler);
1668
1914
  }
1669
- }, [disabled, resizeHandleId, registerResizeHandle]);
1915
+ }, [disabled, resizeHandleId, registerResizeHandleWithParentGroup]);
1670
1916
  useEffect(() => {
1671
- if (disabled || resizeHandler == null || !isDragging) {
1917
+ var _hitAreaMargins$coars, _hitAreaMargins$fine;
1918
+ if (disabled || resizeHandler == null) {
1672
1919
  return;
1673
1920
  }
1674
- const onMove = event => {
1675
- resizeHandler(event);
1676
- };
1677
- const onMouseLeave = event => {
1678
- resizeHandler(event);
1679
- };
1680
1921
  const element = elementRef.current;
1681
1922
  assert(element);
1682
- const targetDocument = element.ownerDocument;
1683
- targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1684
- targetDocument.body.addEventListener("mousemove", onMove);
1685
- targetDocument.body.addEventListener("touchmove", onMove);
1686
- targetDocument.body.addEventListener("mouseleave", onMouseLeave);
1687
- window.addEventListener("mouseup", stopDraggingAndBlur);
1688
- window.addEventListener("touchend", stopDraggingAndBlur);
1689
- return () => {
1690
- targetDocument.body.removeEventListener("contextmenu", stopDraggingAndBlur);
1691
- targetDocument.body.removeEventListener("mousemove", onMove);
1692
- targetDocument.body.removeEventListener("touchmove", onMove);
1693
- targetDocument.body.removeEventListener("mouseleave", onMouseLeave);
1694
- window.removeEventListener("mouseup", stopDraggingAndBlur);
1695
- window.removeEventListener("touchend", stopDraggingAndBlur);
1923
+ const setResizeHandlerState = (action, state, event) => {
1924
+ setState(state);
1925
+ switch (action) {
1926
+ case "down":
1927
+ {
1928
+ startDragging(resizeHandleId, event);
1929
+ break;
1930
+ }
1931
+ case "up":
1932
+ {
1933
+ stopDragging();
1934
+ break;
1935
+ }
1936
+ }
1937
+ switch (state) {
1938
+ case "drag":
1939
+ {
1940
+ resizeHandler(event);
1941
+ break;
1942
+ }
1943
+ }
1696
1944
  };
1697
- }, [direction, disabled, isDragging, resizeHandler, stopDraggingAndBlur]);
1945
+ return registerResizeHandle(resizeHandleId, element, direction, {
1946
+ // Coarse inputs (e.g. finger/touch)
1947
+ coarse: (_hitAreaMargins$coars = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.coarse) !== null && _hitAreaMargins$coars !== void 0 ? _hitAreaMargins$coars : 15,
1948
+ // Fine inputs (e.g. mouse)
1949
+ fine: (_hitAreaMargins$fine = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.fine) !== null && _hitAreaMargins$fine !== void 0 ? _hitAreaMargins$fine : 5
1950
+ }, setResizeHandlerState);
1951
+ }, [direction, disabled, hitAreaMargins, registerResizeHandleWithParentGroup, resizeHandleId, resizeHandler, startDragging, stopDragging]);
1698
1952
  useWindowSplitterResizeHandlerBehavior({
1699
1953
  disabled,
1700
1954
  handleId: resizeHandleId,
@@ -1702,7 +1956,6 @@ function PanelResizeHandle({
1702
1956
  panelGroupElement
1703
1957
  });
1704
1958
  const style = {
1705
- cursor: getCursorStyle(direction),
1706
1959
  touchAction: "none",
1707
1960
  userSelect: "none"
1708
1961
  };
@@ -1712,31 +1965,6 @@ function PanelResizeHandle({
1712
1965
  className: classNameFromProps,
1713
1966
  onBlur: () => setIsFocused(false),
1714
1967
  onFocus: () => setIsFocused(true),
1715
- onMouseDown: event => {
1716
- startDragging(resizeHandleId, event.nativeEvent);
1717
- const callbacks = callbacksRef.current;
1718
- assert(callbacks);
1719
- const {
1720
- onDragging
1721
- } = callbacks;
1722
- if (onDragging) {
1723
- onDragging(true);
1724
- }
1725
- },
1726
- onMouseUp: stopDraggingAndBlur,
1727
- onTouchCancel: stopDraggingAndBlur,
1728
- onTouchEnd: stopDraggingAndBlur,
1729
- onTouchStart: event => {
1730
- startDragging(resizeHandleId, event.nativeEvent);
1731
- const callbacks = callbacksRef.current;
1732
- assert(callbacks);
1733
- const {
1734
- onDragging
1735
- } = callbacks;
1736
- if (onDragging) {
1737
- onDragging(true);
1738
- }
1739
- },
1740
1968
  ref: elementRef,
1741
1969
  role: "separator",
1742
1970
  style: {
@@ -1748,7 +1976,8 @@ function PanelResizeHandle({
1748
1976
  "data-panel-group-direction": direction,
1749
1977
  "data-panel-group-id": groupId,
1750
1978
  "data-resize-handle": "",
1751
- "data-resize-handle-active": isDragging ? "pointer" : isFocused ? "keyboard" : undefined,
1979
+ "data-resize-handle-active": state === "drag" ? "pointer" : isFocused ? "keyboard" : undefined,
1980
+ "data-resize-handle-state": state,
1752
1981
  "data-panel-resize-handle-enabled": !disabled,
1753
1982
  "data-panel-resize-handle-id": resizeHandleId
1754
1983
  });