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.
@@ -204,6 +204,322 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
204
204
  PanelWithForwardedRef.displayName = "Panel";
205
205
  Panel.displayName = "forwardRef(Panel)";
206
206
 
207
+ let currentCursorStyle = null;
208
+ let styleElement = null;
209
+ function getCursorStyle(state, constraintFlags) {
210
+ if (constraintFlags) {
211
+ const horizontalMin = (constraintFlags & EXCEEDED_HORIZONTAL_MIN) !== 0;
212
+ const horizontalMax = (constraintFlags & EXCEEDED_HORIZONTAL_MAX) !== 0;
213
+ const verticalMin = (constraintFlags & EXCEEDED_VERTICAL_MIN) !== 0;
214
+ const verticalMax = (constraintFlags & EXCEEDED_VERTICAL_MAX) !== 0;
215
+ if (horizontalMin) {
216
+ if (verticalMin) {
217
+ return "se-resize";
218
+ } else if (verticalMax) {
219
+ return "ne-resize";
220
+ } else {
221
+ return "e-resize";
222
+ }
223
+ } else if (horizontalMax) {
224
+ if (verticalMin) {
225
+ return "sw-resize";
226
+ } else if (verticalMax) {
227
+ return "nw-resize";
228
+ } else {
229
+ return "w-resize";
230
+ }
231
+ } else if (verticalMin) {
232
+ return "s-resize";
233
+ } else if (verticalMax) {
234
+ return "n-resize";
235
+ }
236
+ }
237
+ switch (state) {
238
+ case "horizontal":
239
+ return "ew-resize";
240
+ case "intersection":
241
+ return "move";
242
+ case "vertical":
243
+ return "ns-resize";
244
+ }
245
+ }
246
+ function resetGlobalCursorStyle() {
247
+ if (styleElement !== null) {
248
+ document.head.removeChild(styleElement);
249
+ currentCursorStyle = null;
250
+ styleElement = null;
251
+ }
252
+ }
253
+ function setGlobalCursorStyle(state, constraintFlags) {
254
+ const style = getCursorStyle(state, constraintFlags);
255
+ if (currentCursorStyle === style) {
256
+ return;
257
+ }
258
+ currentCursorStyle = style;
259
+ if (styleElement === null) {
260
+ styleElement = document.createElement("style");
261
+ document.head.appendChild(styleElement);
262
+ }
263
+ styleElement.innerHTML = `*{cursor: ${style}!important;}`;
264
+ }
265
+
266
+ function isKeyDown(event) {
267
+ return event.type === "keydown";
268
+ }
269
+ function isMouseEvent(event) {
270
+ return event.type.startsWith("mouse");
271
+ }
272
+ function isTouchEvent(event) {
273
+ return event.type.startsWith("touch");
274
+ }
275
+
276
+ function getResizeEventCoordinates(event) {
277
+ if (isMouseEvent(event)) {
278
+ return {
279
+ x: event.pageX,
280
+ y: event.pageY
281
+ };
282
+ } else if (isTouchEvent(event)) {
283
+ const touch = event.touches[0];
284
+ if (touch && touch.pageX && touch.pageY) {
285
+ return {
286
+ x: touch.pageX,
287
+ y: touch.pageY
288
+ };
289
+ }
290
+ }
291
+ return {
292
+ x: Infinity,
293
+ y: Infinity
294
+ };
295
+ }
296
+
297
+ function getInputType() {
298
+ if (typeof matchMedia === "function") {
299
+ return matchMedia("(pointer:coarse)").matches ? "coarse" : "fine";
300
+ }
301
+ }
302
+
303
+ const EXCEEDED_HORIZONTAL_MIN = 0b0001;
304
+ const EXCEEDED_HORIZONTAL_MAX = 0b0010;
305
+ const EXCEEDED_VERTICAL_MIN = 0b0100;
306
+ const EXCEEDED_VERTICAL_MAX = 0b1000;
307
+ const isCoarsePointer = getInputType() === "coarse";
308
+ let intersectingHandles = [];
309
+ let isPointerDown = false;
310
+ let ownerDocumentCounts = new Map();
311
+ let panelConstraintFlags = new Map();
312
+ const registeredResizeHandlers = new Set();
313
+ function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins, setResizeHandlerState) {
314
+ var _ownerDocumentCounts$;
315
+ const {
316
+ ownerDocument
317
+ } = element;
318
+ const data = {
319
+ direction,
320
+ element,
321
+ hitAreaMargins,
322
+ setResizeHandlerState
323
+ };
324
+ const count = (_ownerDocumentCounts$ = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$ !== void 0 ? _ownerDocumentCounts$ : 0;
325
+ ownerDocumentCounts.set(ownerDocument, count + 1);
326
+ registeredResizeHandlers.add(data);
327
+ updateListeners();
328
+ return function unregisterResizeHandle() {
329
+ var _ownerDocumentCounts$2;
330
+ panelConstraintFlags.delete(resizeHandleId);
331
+ registeredResizeHandlers.delete(data);
332
+ const count = (_ownerDocumentCounts$2 = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$2 !== void 0 ? _ownerDocumentCounts$2 : 1;
333
+ ownerDocumentCounts.set(ownerDocument, count - 1);
334
+ updateListeners();
335
+ if (count === 1) {
336
+ ownerDocumentCounts.delete(ownerDocument);
337
+ }
338
+ };
339
+ }
340
+ function handlePointerDown(event) {
341
+ const {
342
+ x,
343
+ y
344
+ } = getResizeEventCoordinates(event);
345
+ isPointerDown = true;
346
+ updateResizeHandlerStates("down", event);
347
+ recalculateIntersectingHandles({
348
+ x,
349
+ y
350
+ });
351
+ updateListeners();
352
+ if (intersectingHandles.length > 0) {
353
+ event.preventDefault();
354
+ }
355
+ }
356
+ function handlePointerMove(event) {
357
+ const {
358
+ x,
359
+ y
360
+ } = getResizeEventCoordinates(event);
361
+ if (isPointerDown) {
362
+ intersectingHandles.forEach(data => {
363
+ const {
364
+ setResizeHandlerState
365
+ } = data;
366
+ setResizeHandlerState("move", "drag", event);
367
+ });
368
+
369
+ // Update cursor based on return value(s) from active handles
370
+ updateCursor();
371
+ } else {
372
+ recalculateIntersectingHandles({
373
+ x,
374
+ y
375
+ });
376
+ updateResizeHandlerStates("move", event);
377
+ updateCursor();
378
+ }
379
+ if (intersectingHandles.length > 0) {
380
+ event.preventDefault();
381
+ }
382
+ }
383
+ function handlePointerUp(event) {
384
+ const {
385
+ x,
386
+ y
387
+ } = getResizeEventCoordinates(event);
388
+ panelConstraintFlags.clear();
389
+ isPointerDown = false;
390
+ if (intersectingHandles.length > 0) {
391
+ event.preventDefault();
392
+ }
393
+ recalculateIntersectingHandles({
394
+ x,
395
+ y
396
+ });
397
+ updateResizeHandlerStates("up", event);
398
+ updateCursor();
399
+ updateListeners();
400
+ }
401
+ function recalculateIntersectingHandles({
402
+ x,
403
+ y
404
+ }) {
405
+ intersectingHandles.splice(0);
406
+ registeredResizeHandlers.forEach(data => {
407
+ const {
408
+ element,
409
+ hitAreaMargins
410
+ } = data;
411
+ const {
412
+ bottom,
413
+ left,
414
+ right,
415
+ top
416
+ } = element.getBoundingClientRect();
417
+ const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
418
+ const intersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
419
+ if (intersects) {
420
+ intersectingHandles.push(data);
421
+ }
422
+ });
423
+ }
424
+ function reportConstraintsViolation(resizeHandleId, flag) {
425
+ panelConstraintFlags.set(resizeHandleId, flag);
426
+ }
427
+ function updateCursor() {
428
+ let intersectsHorizontal = false;
429
+ let intersectsVertical = false;
430
+ intersectingHandles.forEach(data => {
431
+ const {
432
+ direction
433
+ } = data;
434
+ if (direction === "horizontal") {
435
+ intersectsHorizontal = true;
436
+ } else {
437
+ intersectsVertical = true;
438
+ }
439
+ });
440
+ let constraintFlags = 0;
441
+ panelConstraintFlags.forEach(flag => {
442
+ constraintFlags |= flag;
443
+ });
444
+ if (intersectsHorizontal && intersectsVertical) {
445
+ setGlobalCursorStyle("intersection", constraintFlags);
446
+ } else if (intersectsHorizontal) {
447
+ setGlobalCursorStyle("horizontal", constraintFlags);
448
+ } else if (intersectsVertical) {
449
+ setGlobalCursorStyle("vertical", constraintFlags);
450
+ } else {
451
+ resetGlobalCursorStyle();
452
+ }
453
+ }
454
+ function updateListeners() {
455
+ ownerDocumentCounts.forEach((_, ownerDocument) => {
456
+ const {
457
+ body
458
+ } = ownerDocument;
459
+ body.removeEventListener("contextmenu", handlePointerUp);
460
+ body.removeEventListener("mousedown", handlePointerDown);
461
+ body.removeEventListener("mouseleave", handlePointerMove);
462
+ body.removeEventListener("mousemove", handlePointerMove);
463
+ body.removeEventListener("touchmove", handlePointerMove);
464
+ body.removeEventListener("touchstart", handlePointerDown);
465
+ });
466
+ window.removeEventListener("mouseup", handlePointerUp);
467
+ window.removeEventListener("touchcancel", handlePointerUp);
468
+ window.removeEventListener("touchend", handlePointerUp);
469
+ if (registerResizeHandle.length > 0) {
470
+ if (isPointerDown) {
471
+ if (intersectingHandles.length > 0) {
472
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
473
+ const {
474
+ body
475
+ } = ownerDocument;
476
+ if (count > 0) {
477
+ body.addEventListener("contextmenu", handlePointerUp);
478
+ body.addEventListener("mouseleave", handlePointerMove);
479
+ body.addEventListener("mousemove", handlePointerMove);
480
+ body.addEventListener("touchmove", handlePointerMove, {
481
+ passive: false
482
+ });
483
+ }
484
+ });
485
+ }
486
+ window.addEventListener("mouseup", handlePointerUp);
487
+ window.addEventListener("touchcancel", handlePointerUp);
488
+ window.addEventListener("touchend", handlePointerUp);
489
+ } else {
490
+ ownerDocumentCounts.forEach((count, ownerDocument) => {
491
+ const {
492
+ body
493
+ } = ownerDocument;
494
+ if (count > 0) {
495
+ body.addEventListener("mousedown", handlePointerDown);
496
+ body.addEventListener("mousemove", handlePointerMove);
497
+ body.addEventListener("touchmove", handlePointerMove, {
498
+ passive: false
499
+ });
500
+ body.addEventListener("touchstart", handlePointerDown);
501
+ }
502
+ });
503
+ }
504
+ }
505
+ }
506
+ function updateResizeHandlerStates(action, event) {
507
+ registeredResizeHandlers.forEach(data => {
508
+ const {
509
+ setResizeHandlerState
510
+ } = data;
511
+ if (intersectingHandles.includes(data)) {
512
+ if (isPointerDown) {
513
+ setResizeHandlerState(action, "drag", event);
514
+ } else {
515
+ setResizeHandlerState(action, "hover", event);
516
+ }
517
+ } else {
518
+ setResizeHandlerState(action, "inactive", event);
519
+ }
520
+ });
521
+ }
522
+
207
523
  function assert(expectedCondition, message = "Assertion failed!") {
208
524
  if (!expectedCondition) {
209
525
  console.error(message);
@@ -719,27 +1035,13 @@ function areEqual(arrayA, arrayB) {
719
1035
  return true;
720
1036
  }
721
1037
 
722
- function isKeyDown(event) {
723
- return event.type === "keydown";
724
- }
725
- function isMouseEvent(event) {
726
- return event.type.startsWith("mouse");
727
- }
728
- function isTouchEvent(event) {
729
- return event.type.startsWith("touch");
730
- }
731
-
732
1038
  function getResizeEventCursorPosition(direction, event) {
733
1039
  const isHorizontal = direction === "horizontal";
734
- if (isMouseEvent(event)) {
735
- return isHorizontal ? event.clientX : event.clientY;
736
- } else if (isTouchEvent(event)) {
737
- const firstTouch = event.touches[0];
738
- assert(firstTouch);
739
- return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
740
- } else {
741
- throw Error(`Unsupported event type "${event.type}"`);
742
- }
1040
+ const {
1041
+ x,
1042
+ y
1043
+ } = getResizeEventCoordinates(event);
1044
+ return isHorizontal ? x : y;
743
1045
  }
744
1046
 
745
1047
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
@@ -929,44 +1231,6 @@ function computePanelFlexBoxStyle({
929
1231
  };
930
1232
  }
931
1233
 
932
- let currentState = null;
933
- let element = null;
934
- function getCursorStyle(state) {
935
- switch (state) {
936
- case "horizontal":
937
- return "ew-resize";
938
- case "horizontal-max":
939
- return "w-resize";
940
- case "horizontal-min":
941
- return "e-resize";
942
- case "vertical":
943
- return "ns-resize";
944
- case "vertical-max":
945
- return "n-resize";
946
- case "vertical-min":
947
- return "s-resize";
948
- }
949
- }
950
- function resetGlobalCursorStyle() {
951
- if (element !== null) {
952
- document.head.removeChild(element);
953
- currentState = null;
954
- element = null;
955
- }
956
- }
957
- function setGlobalCursorStyle(state) {
958
- if (currentState === state) {
959
- return;
960
- }
961
- currentState = state;
962
- const style = getCursorStyle(state);
963
- if (element === null) {
964
- element = document.createElement("style");
965
- document.head.appendChild(element);
966
- }
967
- element.innerHTML = `*{cursor: ${style}!important;}`;
968
- }
969
-
970
1234
  function debounce(callback, durationMs = 10) {
971
1235
  let timeoutId = null;
972
1236
  let callable = (...args) => {
@@ -1602,18 +1866,15 @@ function PanelGroupWithForwardedRef({
1602
1866
  if (prevDeltaRef.current != delta) {
1603
1867
  prevDeltaRef.current = delta;
1604
1868
  if (!layoutChanged) {
1605
- // If the pointer has moved too far to resize the panel any further,
1606
- // update the cursor style for a visual clue.
1869
+ // If the pointer has moved too far to resize the panel any further, note this so we can update the cursor.
1607
1870
  // This mimics VS Code behavior.
1608
-
1609
1871
  if (isHorizontal) {
1610
- setGlobalCursorStyle(delta < 0 ? "horizontal-min" : "horizontal-max");
1872
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_HORIZONTAL_MIN : EXCEEDED_HORIZONTAL_MAX);
1611
1873
  } else {
1612
- setGlobalCursorStyle(delta < 0 ? "vertical-min" : "vertical-max");
1874
+ reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_VERTICAL_MIN : EXCEEDED_VERTICAL_MAX);
1613
1875
  }
1614
1876
  } else {
1615
- // Reset the cursor style to the the normal resize cursor.
1616
- setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
1877
+ reportConstraintsViolation(dragHandleId, 0);
1617
1878
  }
1618
1879
  }
1619
1880
  }
@@ -1711,7 +1972,6 @@ function PanelGroupWithForwardedRef({
1711
1972
  });
1712
1973
  }, []);
1713
1974
  const stopDragging = useCallback(() => {
1714
- resetGlobalCursorStyle();
1715
1975
  setDragState(null);
1716
1976
  }, []);
1717
1977
  const unregisterPanel = useCallback(panelData => {
@@ -1852,6 +2112,7 @@ function PanelResizeHandle({
1852
2112
  children = null,
1853
2113
  className: classNameFromProps = "",
1854
2114
  disabled = false,
2115
+ hitAreaMargins,
1855
2116
  id: idFromProps,
1856
2117
  onDragging,
1857
2118
  style: styleFromProps = {},
@@ -1874,67 +2135,60 @@ function PanelResizeHandle({
1874
2135
  }
1875
2136
  const {
1876
2137
  direction,
1877
- dragState,
1878
2138
  groupId,
1879
- registerResizeHandle,
2139
+ registerResizeHandle: registerResizeHandleWithParentGroup,
1880
2140
  startDragging,
1881
2141
  stopDragging,
1882
2142
  panelGroupElement
1883
2143
  } = panelGroupContext;
1884
2144
  const resizeHandleId = useUniqueId(idFromProps);
1885
- const isDragging = (dragState === null || dragState === void 0 ? void 0 : dragState.dragHandleId) === resizeHandleId;
2145
+ const [state, setState] = useState("inactive");
1886
2146
  const [isFocused, setIsFocused] = useState(false);
1887
2147
  const [resizeHandler, setResizeHandler] = useState(null);
1888
- const stopDraggingAndBlur = useCallback(() => {
1889
- // Clicking on the drag handle shouldn't leave it focused;
1890
- // That would cause the PanelGroup to think it was still active.
1891
- const element = elementRef.current;
1892
- assert(element);
1893
- element.blur();
1894
- stopDragging();
1895
- const {
1896
- onDragging
1897
- } = callbacksRef.current;
1898
- if (onDragging) {
1899
- onDragging(false);
1900
- }
1901
- }, [stopDragging]);
1902
2148
  useEffect(() => {
1903
2149
  if (disabled) {
1904
2150
  setResizeHandler(null);
1905
2151
  } else {
1906
- const resizeHandler = registerResizeHandle(resizeHandleId);
2152
+ const resizeHandler = registerResizeHandleWithParentGroup(resizeHandleId);
1907
2153
  setResizeHandler(() => resizeHandler);
1908
2154
  }
1909
- }, [disabled, resizeHandleId, registerResizeHandle]);
2155
+ }, [disabled, resizeHandleId, registerResizeHandleWithParentGroup]);
1910
2156
  useEffect(() => {
1911
- if (disabled || resizeHandler == null || !isDragging) {
2157
+ var _hitAreaMargins$coars, _hitAreaMargins$fine;
2158
+ if (disabled || resizeHandler == null) {
1912
2159
  return;
1913
2160
  }
1914
- const onMove = event => {
1915
- resizeHandler(event);
1916
- };
1917
- const onMouseLeave = event => {
1918
- resizeHandler(event);
1919
- };
1920
2161
  const element = elementRef.current;
1921
2162
  assert(element);
1922
- const targetDocument = element.ownerDocument;
1923
- targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1924
- targetDocument.body.addEventListener("mousemove", onMove);
1925
- targetDocument.body.addEventListener("touchmove", onMove);
1926
- targetDocument.body.addEventListener("mouseleave", onMouseLeave);
1927
- window.addEventListener("mouseup", stopDraggingAndBlur);
1928
- window.addEventListener("touchend", stopDraggingAndBlur);
1929
- return () => {
1930
- targetDocument.body.removeEventListener("contextmenu", stopDraggingAndBlur);
1931
- targetDocument.body.removeEventListener("mousemove", onMove);
1932
- targetDocument.body.removeEventListener("touchmove", onMove);
1933
- targetDocument.body.removeEventListener("mouseleave", onMouseLeave);
1934
- window.removeEventListener("mouseup", stopDraggingAndBlur);
1935
- window.removeEventListener("touchend", stopDraggingAndBlur);
2163
+ const setResizeHandlerState = (action, state, event) => {
2164
+ setState(state);
2165
+ switch (action) {
2166
+ case "down":
2167
+ {
2168
+ startDragging(resizeHandleId, event);
2169
+ break;
2170
+ }
2171
+ case "up":
2172
+ {
2173
+ stopDragging();
2174
+ break;
2175
+ }
2176
+ }
2177
+ switch (state) {
2178
+ case "drag":
2179
+ {
2180
+ resizeHandler(event);
2181
+ break;
2182
+ }
2183
+ }
1936
2184
  };
1937
- }, [direction, disabled, isDragging, resizeHandler, stopDraggingAndBlur]);
2185
+ return registerResizeHandle(resizeHandleId, element, direction, {
2186
+ // Coarse inputs (e.g. finger/touch)
2187
+ coarse: (_hitAreaMargins$coars = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.coarse) !== null && _hitAreaMargins$coars !== void 0 ? _hitAreaMargins$coars : 15,
2188
+ // Fine inputs (e.g. mouse)
2189
+ fine: (_hitAreaMargins$fine = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.fine) !== null && _hitAreaMargins$fine !== void 0 ? _hitAreaMargins$fine : 5
2190
+ }, setResizeHandlerState);
2191
+ }, [direction, disabled, hitAreaMargins, registerResizeHandleWithParentGroup, resizeHandleId, resizeHandler, startDragging, stopDragging]);
1938
2192
  useWindowSplitterResizeHandlerBehavior({
1939
2193
  disabled,
1940
2194
  handleId: resizeHandleId,
@@ -1942,7 +2196,6 @@ function PanelResizeHandle({
1942
2196
  panelGroupElement
1943
2197
  });
1944
2198
  const style = {
1945
- cursor: getCursorStyle(direction),
1946
2199
  touchAction: "none",
1947
2200
  userSelect: "none"
1948
2201
  };
@@ -1952,31 +2205,6 @@ function PanelResizeHandle({
1952
2205
  className: classNameFromProps,
1953
2206
  onBlur: () => setIsFocused(false),
1954
2207
  onFocus: () => setIsFocused(true),
1955
- onMouseDown: event => {
1956
- startDragging(resizeHandleId, event.nativeEvent);
1957
- const callbacks = callbacksRef.current;
1958
- assert(callbacks);
1959
- const {
1960
- onDragging
1961
- } = callbacks;
1962
- if (onDragging) {
1963
- onDragging(true);
1964
- }
1965
- },
1966
- onMouseUp: stopDraggingAndBlur,
1967
- onTouchCancel: stopDraggingAndBlur,
1968
- onTouchEnd: stopDraggingAndBlur,
1969
- onTouchStart: event => {
1970
- startDragging(resizeHandleId, event.nativeEvent);
1971
- const callbacks = callbacksRef.current;
1972
- assert(callbacks);
1973
- const {
1974
- onDragging
1975
- } = callbacks;
1976
- if (onDragging) {
1977
- onDragging(true);
1978
- }
1979
- },
1980
2208
  ref: elementRef,
1981
2209
  role: "separator",
1982
2210
  style: {
@@ -1988,7 +2216,8 @@ function PanelResizeHandle({
1988
2216
  "data-panel-group-direction": direction,
1989
2217
  "data-panel-group-id": groupId,
1990
2218
  "data-resize-handle": "",
1991
- "data-resize-handle-active": isDragging ? "pointer" : isFocused ? "keyboard" : undefined,
2219
+ "data-resize-handle-active": state === "drag" ? "pointer" : isFocused ? "keyboard" : undefined,
2220
+ "data-resize-handle-state": state,
1992
2221
  "data-panel-resize-handle-enabled": !disabled,
1993
2222
  "data-panel-resize-handle-id": resizeHandleId
1994
2223
  });