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