react-resizable-panels 1.0.10 → 2.0.0

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.
@@ -187,6 +187,322 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
187
187
  PanelWithForwardedRef.displayName = "Panel";
188
188
  Panel.displayName = "forwardRef(Panel)";
189
189
 
190
+ let currentCursorStyle = null;
191
+ let styleElement = null;
192
+ function getCursorStyle(state, constraintFlags) {
193
+ if (constraintFlags) {
194
+ const horizontalMin = (constraintFlags & EXCEEDED_HORIZONTAL_MIN) !== 0;
195
+ const horizontalMax = (constraintFlags & EXCEEDED_HORIZONTAL_MAX) !== 0;
196
+ const verticalMin = (constraintFlags & EXCEEDED_VERTICAL_MIN) !== 0;
197
+ const verticalMax = (constraintFlags & EXCEEDED_VERTICAL_MAX) !== 0;
198
+ if (horizontalMin) {
199
+ if (verticalMin) {
200
+ return "se-resize";
201
+ } else if (verticalMax) {
202
+ return "ne-resize";
203
+ } else {
204
+ return "e-resize";
205
+ }
206
+ } else if (horizontalMax) {
207
+ if (verticalMin) {
208
+ return "sw-resize";
209
+ } else if (verticalMax) {
210
+ return "nw-resize";
211
+ } else {
212
+ return "w-resize";
213
+ }
214
+ } else if (verticalMin) {
215
+ return "s-resize";
216
+ } else if (verticalMax) {
217
+ return "n-resize";
218
+ }
219
+ }
220
+ switch (state) {
221
+ case "horizontal":
222
+ return "ew-resize";
223
+ case "intersection":
224
+ return "move";
225
+ case "vertical":
226
+ return "ns-resize";
227
+ }
228
+ }
229
+ function resetGlobalCursorStyle() {
230
+ if (styleElement !== null) {
231
+ document.head.removeChild(styleElement);
232
+ currentCursorStyle = null;
233
+ styleElement = null;
234
+ }
235
+ }
236
+ function setGlobalCursorStyle(state, constraintFlags) {
237
+ const style = getCursorStyle(state, constraintFlags);
238
+ if (currentCursorStyle === style) {
239
+ return;
240
+ }
241
+ currentCursorStyle = style;
242
+ if (styleElement === null) {
243
+ styleElement = document.createElement("style");
244
+ document.head.appendChild(styleElement);
245
+ }
246
+ styleElement.innerHTML = `*{cursor: ${style}!important;}`;
247
+ }
248
+
249
+ function isKeyDown(event) {
250
+ return event.type === "keydown";
251
+ }
252
+ function isMouseEvent(event) {
253
+ return event.type.startsWith("mouse");
254
+ }
255
+ function isTouchEvent(event) {
256
+ return event.type.startsWith("touch");
257
+ }
258
+
259
+ function getResizeEventCoordinates(event) {
260
+ if (isMouseEvent(event)) {
261
+ return {
262
+ x: event.pageX,
263
+ y: event.pageY
264
+ };
265
+ } else if (isTouchEvent(event)) {
266
+ const touch = event.touches[0];
267
+ if (touch && touch.pageX && touch.pageY) {
268
+ return {
269
+ x: touch.pageX,
270
+ y: touch.pageY
271
+ };
272
+ }
273
+ }
274
+ return {
275
+ x: Infinity,
276
+ y: Infinity
277
+ };
278
+ }
279
+
280
+ function getInputType() {
281
+ if (typeof matchMedia === "function") {
282
+ return matchMedia("(pointer:coarse)").matches ? "coarse" : "fine";
283
+ }
284
+ }
285
+
286
+ const EXCEEDED_HORIZONTAL_MIN = 0b0001;
287
+ const EXCEEDED_HORIZONTAL_MAX = 0b0010;
288
+ const EXCEEDED_VERTICAL_MIN = 0b0100;
289
+ const EXCEEDED_VERTICAL_MAX = 0b1000;
290
+ const isCoarsePointer = getInputType() === "coarse";
291
+ let intersectingHandles = [];
292
+ let isPointerDown = false;
293
+ let ownerDocumentCounts = new Map();
294
+ let panelConstraintFlags = new Map();
295
+ const registeredResizeHandlers = new Set();
296
+ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins, setResizeHandlerState) {
297
+ var _ownerDocumentCounts$;
298
+ const {
299
+ ownerDocument
300
+ } = element;
301
+ const data = {
302
+ direction,
303
+ element,
304
+ hitAreaMargins,
305
+ setResizeHandlerState
306
+ };
307
+ const count = (_ownerDocumentCounts$ = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$ !== void 0 ? _ownerDocumentCounts$ : 0;
308
+ ownerDocumentCounts.set(ownerDocument, count + 1);
309
+ registeredResizeHandlers.add(data);
310
+ updateListeners();
311
+ return function unregisterResizeHandle() {
312
+ var _ownerDocumentCounts$2;
313
+ panelConstraintFlags.delete(resizeHandleId);
314
+ registeredResizeHandlers.delete(data);
315
+ const count = (_ownerDocumentCounts$2 = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$2 !== void 0 ? _ownerDocumentCounts$2 : 1;
316
+ ownerDocumentCounts.set(ownerDocument, count - 1);
317
+ updateListeners();
318
+ if (count === 1) {
319
+ ownerDocumentCounts.delete(ownerDocument);
320
+ }
321
+ };
322
+ }
323
+ function handlePointerDown(event) {
324
+ const {
325
+ x,
326
+ y
327
+ } = getResizeEventCoordinates(event);
328
+ isPointerDown = true;
329
+ updateResizeHandlerStates("down", event);
330
+ recalculateIntersectingHandles({
331
+ x,
332
+ y
333
+ });
334
+ updateListeners();
335
+ if (intersectingHandles.length > 0) {
336
+ event.preventDefault();
337
+ }
338
+ }
339
+ function handlePointerMove(event) {
340
+ const {
341
+ x,
342
+ y
343
+ } = getResizeEventCoordinates(event);
344
+ if (isPointerDown) {
345
+ intersectingHandles.forEach(data => {
346
+ const {
347
+ setResizeHandlerState
348
+ } = data;
349
+ setResizeHandlerState("move", "drag", event);
350
+ });
351
+
352
+ // Update cursor based on return value(s) from active handles
353
+ updateCursor();
354
+ } else {
355
+ recalculateIntersectingHandles({
356
+ x,
357
+ y
358
+ });
359
+ updateResizeHandlerStates("move", event);
360
+ updateCursor();
361
+ }
362
+ if (intersectingHandles.length > 0) {
363
+ event.preventDefault();
364
+ }
365
+ }
366
+ function handlePointerUp(event) {
367
+ const {
368
+ x,
369
+ y
370
+ } = getResizeEventCoordinates(event);
371
+ panelConstraintFlags.clear();
372
+ isPointerDown = false;
373
+ if (intersectingHandles.length > 0) {
374
+ event.preventDefault();
375
+ }
376
+ recalculateIntersectingHandles({
377
+ x,
378
+ y
379
+ });
380
+ updateResizeHandlerStates("up", event);
381
+ updateCursor();
382
+ updateListeners();
383
+ }
384
+ function recalculateIntersectingHandles({
385
+ x,
386
+ y
387
+ }) {
388
+ intersectingHandles.splice(0);
389
+ registeredResizeHandlers.forEach(data => {
390
+ const {
391
+ element,
392
+ hitAreaMargins
393
+ } = data;
394
+ const {
395
+ bottom,
396
+ left,
397
+ right,
398
+ top
399
+ } = element.getBoundingClientRect();
400
+ const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
401
+ const intersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
402
+ if (intersects) {
403
+ intersectingHandles.push(data);
404
+ }
405
+ });
406
+ }
407
+ function reportConstraintsViolation(resizeHandleId, flag) {
408
+ panelConstraintFlags.set(resizeHandleId, flag);
409
+ }
410
+ function updateCursor() {
411
+ let intersectsHorizontal = false;
412
+ let intersectsVertical = false;
413
+ intersectingHandles.forEach(data => {
414
+ const {
415
+ direction
416
+ } = data;
417
+ if (direction === "horizontal") {
418
+ intersectsHorizontal = true;
419
+ } else {
420
+ intersectsVertical = true;
421
+ }
422
+ });
423
+ let constraintFlags = 0;
424
+ panelConstraintFlags.forEach(flag => {
425
+ constraintFlags |= flag;
426
+ });
427
+ if (intersectsHorizontal && intersectsVertical) {
428
+ setGlobalCursorStyle("intersection", constraintFlags);
429
+ } else if (intersectsHorizontal) {
430
+ setGlobalCursorStyle("horizontal", constraintFlags);
431
+ } else if (intersectsVertical) {
432
+ setGlobalCursorStyle("vertical", constraintFlags);
433
+ } else {
434
+ resetGlobalCursorStyle();
435
+ }
436
+ }
437
+ function updateListeners() {
438
+ ownerDocumentCounts.forEach((_, ownerDocument) => {
439
+ const {
440
+ body
441
+ } = ownerDocument;
442
+ body.removeEventListener("contextmenu", handlePointerUp);
443
+ body.removeEventListener("mousedown", handlePointerDown);
444
+ body.removeEventListener("mouseleave", handlePointerMove);
445
+ body.removeEventListener("mousemove", handlePointerMove);
446
+ body.removeEventListener("touchmove", handlePointerMove);
447
+ body.removeEventListener("touchstart", handlePointerDown);
448
+ });
449
+ window.removeEventListener("mouseup", handlePointerUp);
450
+ window.removeEventListener("touchcancel", handlePointerUp);
451
+ window.removeEventListener("touchend", handlePointerUp);
452
+ if (registerResizeHandle.length > 0) {
453
+ if (isPointerDown) {
454
+ if (intersectingHandles.length > 0) {
455
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
456
+ const {
457
+ body
458
+ } = ownerDocument;
459
+ if (count > 0) {
460
+ body.addEventListener("contextmenu", handlePointerUp);
461
+ body.addEventListener("mouseleave", handlePointerMove);
462
+ body.addEventListener("mousemove", handlePointerMove);
463
+ body.addEventListener("touchmove", handlePointerMove, {
464
+ passive: false
465
+ });
466
+ }
467
+ });
468
+ }
469
+ window.addEventListener("mouseup", handlePointerUp);
470
+ window.addEventListener("touchcancel", handlePointerUp);
471
+ window.addEventListener("touchend", handlePointerUp);
472
+ } else {
473
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
474
+ const {
475
+ body
476
+ } = ownerDocument;
477
+ if (count > 0) {
478
+ body.addEventListener("mousedown", handlePointerDown);
479
+ body.addEventListener("mousemove", handlePointerMove);
480
+ body.addEventListener("touchmove", handlePointerMove, {
481
+ passive: false
482
+ });
483
+ body.addEventListener("touchstart", handlePointerDown);
484
+ }
485
+ });
486
+ }
487
+ }
488
+ }
489
+ function updateResizeHandlerStates(action, event) {
490
+ registeredResizeHandlers.forEach(data => {
491
+ const {
492
+ setResizeHandlerState
493
+ } = data;
494
+ if (intersectingHandles.includes(data)) {
495
+ if (isPointerDown) {
496
+ setResizeHandlerState(action, "drag", event);
497
+ } else {
498
+ setResizeHandlerState(action, "hover", event);
499
+ }
500
+ } else {
501
+ setResizeHandlerState(action, "inactive", event);
502
+ }
503
+ });
504
+ }
505
+
190
506
  function assert(expectedCondition, message = "Assertion failed!") {
191
507
  if (!expectedCondition) {
192
508
  console.error(message);
@@ -702,27 +1018,13 @@ function areEqual(arrayA, arrayB) {
702
1018
  return true;
703
1019
  }
704
1020
 
705
- function isKeyDown(event) {
706
- return event.type === "keydown";
707
- }
708
- function isMouseEvent(event) {
709
- return event.type.startsWith("mouse");
710
- }
711
- function isTouchEvent(event) {
712
- return event.type.startsWith("touch");
713
- }
714
-
715
1021
  function getResizeEventCursorPosition(direction, event) {
716
1022
  const isHorizontal = direction === "horizontal";
717
- if (isMouseEvent(event)) {
718
- return isHorizontal ? event.clientX : event.clientY;
719
- } else if (isTouchEvent(event)) {
720
- const firstTouch = event.touches[0];
721
- assert(firstTouch);
722
- return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
723
- } else {
724
- throw Error(`Unsupported event type "${event.type}"`);
725
- }
1023
+ const {
1024
+ x,
1025
+ y
1026
+ } = getResizeEventCoordinates(event);
1027
+ return isHorizontal ? x : y;
726
1028
  }
727
1029
 
728
1030
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
@@ -912,44 +1214,6 @@ function computePanelFlexBoxStyle({
912
1214
  };
913
1215
  }
914
1216
 
915
- let currentState = null;
916
- let element = null;
917
- function getCursorStyle(state) {
918
- switch (state) {
919
- case "horizontal":
920
- return "ew-resize";
921
- case "horizontal-max":
922
- return "w-resize";
923
- case "horizontal-min":
924
- return "e-resize";
925
- case "vertical":
926
- return "ns-resize";
927
- case "vertical-max":
928
- return "n-resize";
929
- case "vertical-min":
930
- return "s-resize";
931
- }
932
- }
933
- function resetGlobalCursorStyle() {
934
- if (element !== null) {
935
- document.head.removeChild(element);
936
- currentState = null;
937
- element = null;
938
- }
939
- }
940
- function setGlobalCursorStyle(state) {
941
- if (currentState === state) {
942
- return;
943
- }
944
- currentState = state;
945
- const style = getCursorStyle(state);
946
- if (element === null) {
947
- element = document.createElement("style");
948
- document.head.appendChild(element);
949
- }
950
- element.innerHTML = `*{cursor: ${style}!important;}`;
951
- }
952
-
953
1217
  function debounce(callback, durationMs = 10) {
954
1218
  let timeoutId = null;
955
1219
  let callable = (...args) => {
@@ -1585,18 +1849,15 @@ function PanelGroupWithForwardedRef({
1585
1849
  if (prevDeltaRef.current != delta) {
1586
1850
  prevDeltaRef.current = delta;
1587
1851
  if (!layoutChanged) {
1588
- // If the pointer has moved too far to resize the panel any further,
1589
- // update the cursor style for a visual clue.
1852
+ // If the pointer has moved too far to resize the panel any further, note this so we can update the cursor.
1590
1853
  // This mimics VS Code behavior.
1591
-
1592
1854
  if (isHorizontal) {
1593
- setGlobalCursorStyle(delta < 0 ? "horizontal-min" : "horizontal-max");
1855
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_HORIZONTAL_MIN : EXCEEDED_HORIZONTAL_MAX);
1594
1856
  } else {
1595
- setGlobalCursorStyle(delta < 0 ? "vertical-min" : "vertical-max");
1857
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_VERTICAL_MIN : EXCEEDED_VERTICAL_MAX);
1596
1858
  }
1597
1859
  } else {
1598
- // Reset the cursor style to the the normal resize cursor.
1599
- setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
1860
+ reportConstraintsViolation(dragHandleId, 0);
1600
1861
  }
1601
1862
  }
1602
1863
  }
@@ -1694,7 +1955,6 @@ function PanelGroupWithForwardedRef({
1694
1955
  });
1695
1956
  }, []);
1696
1957
  const stopDragging = useCallback(() => {
1697
- resetGlobalCursorStyle();
1698
1958
  setDragState(null);
1699
1959
  }, []);
1700
1960
  const unregisterPanel = useCallback(panelData => {
@@ -1835,6 +2095,7 @@ function PanelResizeHandle({
1835
2095
  children = null,
1836
2096
  className: classNameFromProps = "",
1837
2097
  disabled = false,
2098
+ hitAreaMargins,
1838
2099
  id: idFromProps,
1839
2100
  onDragging,
1840
2101
  style: styleFromProps = {},
@@ -1857,67 +2118,60 @@ function PanelResizeHandle({
1857
2118
  }
1858
2119
  const {
1859
2120
  direction,
1860
- dragState,
1861
2121
  groupId,
1862
- registerResizeHandle,
2122
+ registerResizeHandle: registerResizeHandleWithParentGroup,
1863
2123
  startDragging,
1864
2124
  stopDragging,
1865
2125
  panelGroupElement
1866
2126
  } = panelGroupContext;
1867
2127
  const resizeHandleId = useUniqueId(idFromProps);
1868
- const isDragging = (dragState === null || dragState === void 0 ? void 0 : dragState.dragHandleId) === resizeHandleId;
2128
+ const [state, setState] = useState("inactive");
1869
2129
  const [isFocused, setIsFocused] = useState(false);
1870
2130
  const [resizeHandler, setResizeHandler] = useState(null);
1871
- const stopDraggingAndBlur = useCallback(() => {
1872
- // Clicking on the drag handle shouldn't leave it focused;
1873
- // That would cause the PanelGroup to think it was still active.
1874
- const element = elementRef.current;
1875
- assert(element);
1876
- element.blur();
1877
- stopDragging();
1878
- const {
1879
- onDragging
1880
- } = callbacksRef.current;
1881
- if (onDragging) {
1882
- onDragging(false);
1883
- }
1884
- }, [stopDragging]);
1885
2131
  useEffect(() => {
1886
2132
  if (disabled) {
1887
2133
  setResizeHandler(null);
1888
2134
  } else {
1889
- const resizeHandler = registerResizeHandle(resizeHandleId);
2135
+ const resizeHandler = registerResizeHandleWithParentGroup(resizeHandleId);
1890
2136
  setResizeHandler(() => resizeHandler);
1891
2137
  }
1892
- }, [disabled, resizeHandleId, registerResizeHandle]);
2138
+ }, [disabled, resizeHandleId, registerResizeHandleWithParentGroup]);
1893
2139
  useEffect(() => {
1894
- if (disabled || resizeHandler == null || !isDragging) {
2140
+ var _hitAreaMargins$coars, _hitAreaMargins$fine;
2141
+ if (disabled || resizeHandler == null) {
1895
2142
  return;
1896
2143
  }
1897
- const onMove = event => {
1898
- resizeHandler(event);
1899
- };
1900
- const onMouseLeave = event => {
1901
- resizeHandler(event);
1902
- };
1903
2144
  const element = elementRef.current;
1904
2145
  assert(element);
1905
- const targetDocument = element.ownerDocument;
1906
- targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1907
- targetDocument.body.addEventListener("mousemove", onMove);
1908
- targetDocument.body.addEventListener("touchmove", onMove);
1909
- targetDocument.body.addEventListener("mouseleave", onMouseLeave);
1910
- window.addEventListener("mouseup", stopDraggingAndBlur);
1911
- window.addEventListener("touchend", stopDraggingAndBlur);
1912
- return () => {
1913
- targetDocument.body.removeEventListener("contextmenu", stopDraggingAndBlur);
1914
- targetDocument.body.removeEventListener("mousemove", onMove);
1915
- targetDocument.body.removeEventListener("touchmove", onMove);
1916
- targetDocument.body.removeEventListener("mouseleave", onMouseLeave);
1917
- window.removeEventListener("mouseup", stopDraggingAndBlur);
1918
- window.removeEventListener("touchend", stopDraggingAndBlur);
2146
+ const setResizeHandlerState = (action, state, event) => {
2147
+ setState(state);
2148
+ switch (action) {
2149
+ case "down":
2150
+ {
2151
+ startDragging(resizeHandleId, event);
2152
+ break;
2153
+ }
2154
+ case "up":
2155
+ {
2156
+ stopDragging();
2157
+ break;
2158
+ }
2159
+ }
2160
+ switch (state) {
2161
+ case "drag":
2162
+ {
2163
+ resizeHandler(event);
2164
+ break;
2165
+ }
2166
+ }
1919
2167
  };
1920
- }, [direction, disabled, isDragging, resizeHandler, stopDraggingAndBlur]);
2168
+ return registerResizeHandle(resizeHandleId, element, direction, {
2169
+ // Coarse inputs (e.g. finger/touch)
2170
+ coarse: (_hitAreaMargins$coars = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.coarse) !== null && _hitAreaMargins$coars !== void 0 ? _hitAreaMargins$coars : 15,
2171
+ // Fine inputs (e.g. mouse)
2172
+ fine: (_hitAreaMargins$fine = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.fine) !== null && _hitAreaMargins$fine !== void 0 ? _hitAreaMargins$fine : 5
2173
+ }, setResizeHandlerState);
2174
+ }, [direction, disabled, hitAreaMargins, registerResizeHandleWithParentGroup, resizeHandleId, resizeHandler, startDragging, stopDragging]);
1921
2175
  useWindowSplitterResizeHandlerBehavior({
1922
2176
  disabled,
1923
2177
  handleId: resizeHandleId,
@@ -1925,7 +2179,6 @@ function PanelResizeHandle({
1925
2179
  panelGroupElement
1926
2180
  });
1927
2181
  const style = {
1928
- cursor: getCursorStyle(direction),
1929
2182
  touchAction: "none",
1930
2183
  userSelect: "none"
1931
2184
  };
@@ -1935,31 +2188,6 @@ function PanelResizeHandle({
1935
2188
  className: classNameFromProps,
1936
2189
  onBlur: () => setIsFocused(false),
1937
2190
  onFocus: () => setIsFocused(true),
1938
- onMouseDown: event => {
1939
- startDragging(resizeHandleId, event.nativeEvent);
1940
- const callbacks = callbacksRef.current;
1941
- assert(callbacks);
1942
- const {
1943
- onDragging
1944
- } = callbacks;
1945
- if (onDragging) {
1946
- onDragging(true);
1947
- }
1948
- },
1949
- onMouseUp: stopDraggingAndBlur,
1950
- onTouchCancel: stopDraggingAndBlur,
1951
- onTouchEnd: stopDraggingAndBlur,
1952
- onTouchStart: event => {
1953
- startDragging(resizeHandleId, event.nativeEvent);
1954
- const callbacks = callbacksRef.current;
1955
- assert(callbacks);
1956
- const {
1957
- onDragging
1958
- } = callbacks;
1959
- if (onDragging) {
1960
- onDragging(true);
1961
- }
1962
- },
1963
2191
  ref: elementRef,
1964
2192
  role: "separator",
1965
2193
  style: {
@@ -1971,7 +2199,8 @@ function PanelResizeHandle({
1971
2199
  "data-panel-group-direction": direction,
1972
2200
  "data-panel-group-id": groupId,
1973
2201
  "data-resize-handle": "",
1974
- "data-resize-handle-active": isDragging ? "pointer" : isFocused ? "keyboard" : undefined,
2202
+ "data-resize-handle-active": state === "drag" ? "pointer" : isFocused ? "keyboard" : undefined,
2203
+ "data-resize-handle-state": state,
1975
2204
  "data-panel-resize-handle-enabled": !disabled,
1976
2205
  "data-panel-resize-handle-id": resizeHandleId
1977
2206
  });