react-resizable-panels 2.0.20 → 2.0.22

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.22
4
+
5
+ - Force eager layout re-calculation after panel added/removed (#375)
6
+
7
+ ## 2.0.21
8
+
9
+ - Handle pointer event edge case with different origin iframes (#374)
10
+
3
11
  ## 2.0.20
4
12
 
5
13
  - Reset global cursor if an active resize handle is unmounted (#313)
@@ -492,6 +492,13 @@ function handlePointerMove(event) {
492
492
  x,
493
493
  y
494
494
  } = getResizeEventCoordinates(event);
495
+
496
+ // Edge case (see #340)
497
+ // Detect when the pointer has been released outside an iframe on a different domain
498
+ if (event.buttons === 0) {
499
+ isPointerDown = false;
500
+ updateResizeHandlerStates("up", event);
501
+ }
495
502
  if (!isPointerDown) {
496
503
  const {
497
504
  target
@@ -680,6 +687,11 @@ function updateResizeHandlerStates(action, event) {
680
687
  });
681
688
  }
682
689
 
690
+ function useForceUpdate() {
691
+ const [_, setCount] = useState(0);
692
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
693
+ }
694
+
683
695
  function assert(expectedCondition, message) {
684
696
  if (!expectedCondition) {
685
697
  console.error(message);
@@ -1589,6 +1601,7 @@ function PanelGroupWithForwardedRef({
1589
1601
  const panelGroupElementRef = useRef(null);
1590
1602
  const [dragState, setDragState] = useState(null);
1591
1603
  const [layout, setLayout] = useState([]);
1604
+ const forceUpdate = useForceUpdate();
1592
1605
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1593
1606
  const panelSizeBeforeCollapseRef = useRef(new Map());
1594
1607
  const prevDeltaRef = useRef(0);
@@ -1851,7 +1864,8 @@ function PanelGroupWithForwardedRef({
1851
1864
  }
1852
1865
  });
1853
1866
  eagerValuesRef.current.panelDataArrayChanged = true;
1854
- }, []);
1867
+ forceUpdate();
1868
+ }, [forceUpdate]);
1855
1869
 
1856
1870
  // (Re)calculate group layout whenever panels are registered or unregistered.
1857
1871
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1931,9 +1945,6 @@ function PanelGroupWithForwardedRef({
1931
1945
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1932
1946
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1933
1947
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1934
- if (delta === 0) {
1935
- return;
1936
- }
1937
1948
 
1938
1949
  // Support RTL layouts
1939
1950
  const isHorizontal = direction === "horizontal";
@@ -2086,8 +2097,9 @@ function PanelGroupWithForwardedRef({
2086
2097
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2087
2098
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2088
2099
  eagerValuesRef.current.panelDataArrayChanged = true;
2100
+ forceUpdate();
2089
2101
  }
2090
- }, []);
2102
+ }, [forceUpdate]);
2091
2103
  const context = useMemo(() => ({
2092
2104
  collapsePanel,
2093
2105
  direction,
@@ -498,6 +498,13 @@ function handlePointerMove(event) {
498
498
  x,
499
499
  y
500
500
  } = getResizeEventCoordinates(event);
501
+
502
+ // Edge case (see #340)
503
+ // Detect when the pointer has been released outside an iframe on a different domain
504
+ if (event.buttons === 0) {
505
+ isPointerDown = false;
506
+ updateResizeHandlerStates("up", event);
507
+ }
501
508
  if (!isPointerDown) {
502
509
  const {
503
510
  target
@@ -686,6 +693,11 @@ function updateResizeHandlerStates(action, event) {
686
693
  });
687
694
  }
688
695
 
696
+ function useForceUpdate() {
697
+ const [_, setCount] = useState(0);
698
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
699
+ }
700
+
689
701
  function assert(expectedCondition, message) {
690
702
  if (!expectedCondition) {
691
703
  console.error(message);
@@ -1653,6 +1665,7 @@ function PanelGroupWithForwardedRef({
1653
1665
  const panelGroupElementRef = useRef(null);
1654
1666
  const [dragState, setDragState] = useState(null);
1655
1667
  const [layout, setLayout] = useState([]);
1668
+ const forceUpdate = useForceUpdate();
1656
1669
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1657
1670
  const panelSizeBeforeCollapseRef = useRef(new Map());
1658
1671
  const prevDeltaRef = useRef(0);
@@ -1957,7 +1970,8 @@ function PanelGroupWithForwardedRef({
1957
1970
  }
1958
1971
  });
1959
1972
  eagerValuesRef.current.panelDataArrayChanged = true;
1960
- }, []);
1973
+ forceUpdate();
1974
+ }, [forceUpdate]);
1961
1975
 
1962
1976
  // (Re)calculate group layout whenever panels are registered or unregistered.
1963
1977
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2037,9 +2051,6 @@ function PanelGroupWithForwardedRef({
2037
2051
  } = dragState !== null && dragState !== void 0 ? dragState : {};
2038
2052
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
2039
2053
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
2040
- if (delta === 0) {
2041
- return;
2042
- }
2043
2054
 
2044
2055
  // Support RTL layouts
2045
2056
  const isHorizontal = direction === "horizontal";
@@ -2192,8 +2203,9 @@ function PanelGroupWithForwardedRef({
2192
2203
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2193
2204
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2194
2205
  eagerValuesRef.current.panelDataArrayChanged = true;
2206
+ forceUpdate();
2195
2207
  }
2196
- }, []);
2208
+ }, [forceUpdate]);
2197
2209
  const context = useMemo(() => ({
2198
2210
  collapsePanel,
2199
2211
  direction,
@@ -474,6 +474,13 @@ function handlePointerMove(event) {
474
474
  x,
475
475
  y
476
476
  } = getResizeEventCoordinates(event);
477
+
478
+ // Edge case (see #340)
479
+ // Detect when the pointer has been released outside an iframe on a different domain
480
+ if (event.buttons === 0) {
481
+ isPointerDown = false;
482
+ updateResizeHandlerStates("up", event);
483
+ }
477
484
  if (!isPointerDown) {
478
485
  const {
479
486
  target
@@ -662,6 +669,11 @@ function updateResizeHandlerStates(action, event) {
662
669
  });
663
670
  }
664
671
 
672
+ function useForceUpdate() {
673
+ const [_, setCount] = useState(0);
674
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
675
+ }
676
+
665
677
  function assert(expectedCondition, message) {
666
678
  if (!expectedCondition) {
667
679
  console.error(message);
@@ -1629,6 +1641,7 @@ function PanelGroupWithForwardedRef({
1629
1641
  const panelGroupElementRef = useRef(null);
1630
1642
  const [dragState, setDragState] = useState(null);
1631
1643
  const [layout, setLayout] = useState([]);
1644
+ const forceUpdate = useForceUpdate();
1632
1645
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1633
1646
  const panelSizeBeforeCollapseRef = useRef(new Map());
1634
1647
  const prevDeltaRef = useRef(0);
@@ -1933,7 +1946,8 @@ function PanelGroupWithForwardedRef({
1933
1946
  }
1934
1947
  });
1935
1948
  eagerValuesRef.current.panelDataArrayChanged = true;
1936
- }, []);
1949
+ forceUpdate();
1950
+ }, [forceUpdate]);
1937
1951
 
1938
1952
  // (Re)calculate group layout whenever panels are registered or unregistered.
1939
1953
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2013,9 +2027,6 @@ function PanelGroupWithForwardedRef({
2013
2027
  } = dragState !== null && dragState !== void 0 ? dragState : {};
2014
2028
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
2015
2029
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
2016
- if (delta === 0) {
2017
- return;
2018
- }
2019
2030
 
2020
2031
  // Support RTL layouts
2021
2032
  const isHorizontal = direction === "horizontal";
@@ -2168,8 +2179,9 @@ function PanelGroupWithForwardedRef({
2168
2179
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2169
2180
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2170
2181
  eagerValuesRef.current.panelDataArrayChanged = true;
2182
+ forceUpdate();
2171
2183
  }
2172
- }, []);
2184
+ }, [forceUpdate]);
2173
2185
  const context = useMemo(() => ({
2174
2186
  collapsePanel,
2175
2187
  direction,
@@ -468,6 +468,13 @@ function handlePointerMove(event) {
468
468
  x,
469
469
  y
470
470
  } = getResizeEventCoordinates(event);
471
+
472
+ // Edge case (see #340)
473
+ // Detect when the pointer has been released outside an iframe on a different domain
474
+ if (event.buttons === 0) {
475
+ isPointerDown = false;
476
+ updateResizeHandlerStates("up", event);
477
+ }
471
478
  if (!isPointerDown) {
472
479
  const {
473
480
  target
@@ -656,6 +663,11 @@ function updateResizeHandlerStates(action, event) {
656
663
  });
657
664
  }
658
665
 
666
+ function useForceUpdate() {
667
+ const [_, setCount] = useState(0);
668
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
669
+ }
670
+
659
671
  function assert(expectedCondition, message) {
660
672
  if (!expectedCondition) {
661
673
  console.error(message);
@@ -1565,6 +1577,7 @@ function PanelGroupWithForwardedRef({
1565
1577
  const panelGroupElementRef = useRef(null);
1566
1578
  const [dragState, setDragState] = useState(null);
1567
1579
  const [layout, setLayout] = useState([]);
1580
+ const forceUpdate = useForceUpdate();
1568
1581
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1569
1582
  const panelSizeBeforeCollapseRef = useRef(new Map());
1570
1583
  const prevDeltaRef = useRef(0);
@@ -1827,7 +1840,8 @@ function PanelGroupWithForwardedRef({
1827
1840
  }
1828
1841
  });
1829
1842
  eagerValuesRef.current.panelDataArrayChanged = true;
1830
- }, []);
1843
+ forceUpdate();
1844
+ }, [forceUpdate]);
1831
1845
 
1832
1846
  // (Re)calculate group layout whenever panels are registered or unregistered.
1833
1847
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1907,9 +1921,6 @@ function PanelGroupWithForwardedRef({
1907
1921
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1908
1922
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1909
1923
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1910
- if (delta === 0) {
1911
- return;
1912
- }
1913
1924
 
1914
1925
  // Support RTL layouts
1915
1926
  const isHorizontal = direction === "horizontal";
@@ -2062,8 +2073,9 @@ function PanelGroupWithForwardedRef({
2062
2073
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2063
2074
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2064
2075
  eagerValuesRef.current.panelDataArrayChanged = true;
2076
+ forceUpdate();
2065
2077
  }
2066
- }, []);
2078
+ }, [forceUpdate]);
2067
2079
  const context = useMemo(() => ({
2068
2080
  collapsePanel,
2069
2081
  direction,
@@ -494,6 +494,13 @@ function handlePointerMove(event) {
494
494
  x,
495
495
  y
496
496
  } = getResizeEventCoordinates(event);
497
+
498
+ // Edge case (see #340)
499
+ // Detect when the pointer has been released outside an iframe on a different domain
500
+ if (event.buttons === 0) {
501
+ isPointerDown = false;
502
+ updateResizeHandlerStates("up", event);
503
+ }
497
504
  if (!isPointerDown) {
498
505
  const {
499
506
  target
@@ -682,6 +689,11 @@ function updateResizeHandlerStates(action, event) {
682
689
  });
683
690
  }
684
691
 
692
+ function useForceUpdate() {
693
+ const [_, setCount] = useState(0);
694
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
695
+ }
696
+
685
697
  function assert(expectedCondition, message) {
686
698
  if (!expectedCondition) {
687
699
  console.error(message);
@@ -1591,6 +1603,7 @@ function PanelGroupWithForwardedRef({
1591
1603
  const panelGroupElementRef = useRef(null);
1592
1604
  const [dragState, setDragState] = useState(null);
1593
1605
  const [layout, setLayout] = useState([]);
1606
+ const forceUpdate = useForceUpdate();
1594
1607
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1595
1608
  const panelSizeBeforeCollapseRef = useRef(new Map());
1596
1609
  const prevDeltaRef = useRef(0);
@@ -1853,7 +1866,8 @@ function PanelGroupWithForwardedRef({
1853
1866
  }
1854
1867
  });
1855
1868
  eagerValuesRef.current.panelDataArrayChanged = true;
1856
- }, []);
1869
+ forceUpdate();
1870
+ }, [forceUpdate]);
1857
1871
 
1858
1872
  // (Re)calculate group layout whenever panels are registered or unregistered.
1859
1873
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1933,9 +1947,6 @@ function PanelGroupWithForwardedRef({
1933
1947
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1934
1948
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1935
1949
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1936
- if (delta === 0) {
1937
- return;
1938
- }
1939
1950
 
1940
1951
  // Support RTL layouts
1941
1952
  const isHorizontal = direction === "horizontal";
@@ -2088,8 +2099,9 @@ function PanelGroupWithForwardedRef({
2088
2099
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2089
2100
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2090
2101
  eagerValuesRef.current.panelDataArrayChanged = true;
2102
+ forceUpdate();
2091
2103
  }
2092
- }, []);
2104
+ }, [forceUpdate]);
2093
2105
  const context = useMemo(() => ({
2094
2106
  collapsePanel,
2095
2107
  direction,
@@ -505,6 +505,13 @@ function handlePointerMove(event) {
505
505
  x,
506
506
  y
507
507
  } = getResizeEventCoordinates(event);
508
+
509
+ // Edge case (see #340)
510
+ // Detect when the pointer has been released outside an iframe on a different domain
511
+ if (event.buttons === 0) {
512
+ isPointerDown = false;
513
+ updateResizeHandlerStates("up", event);
514
+ }
508
515
  if (!isPointerDown) {
509
516
  const {
510
517
  target
@@ -693,6 +700,11 @@ function updateResizeHandlerStates(action, event) {
693
700
  });
694
701
  }
695
702
 
703
+ function useForceUpdate() {
704
+ const [_, setCount] = useState(0);
705
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
706
+ }
707
+
696
708
  function assert(expectedCondition, message) {
697
709
  if (!expectedCondition) {
698
710
  console.error(message);
@@ -1660,6 +1672,7 @@ function PanelGroupWithForwardedRef({
1660
1672
  const panelGroupElementRef = useRef(null);
1661
1673
  const [dragState, setDragState] = useState(null);
1662
1674
  const [layout, setLayout] = useState([]);
1675
+ const forceUpdate = useForceUpdate();
1663
1676
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1664
1677
  const panelSizeBeforeCollapseRef = useRef(new Map());
1665
1678
  const prevDeltaRef = useRef(0);
@@ -1964,7 +1977,8 @@ function PanelGroupWithForwardedRef({
1964
1977
  }
1965
1978
  });
1966
1979
  eagerValuesRef.current.panelDataArrayChanged = true;
1967
- }, []);
1980
+ forceUpdate();
1981
+ }, [forceUpdate]);
1968
1982
 
1969
1983
  // (Re)calculate group layout whenever panels are registered or unregistered.
1970
1984
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2044,9 +2058,6 @@ function PanelGroupWithForwardedRef({
2044
2058
  } = dragState !== null && dragState !== void 0 ? dragState : {};
2045
2059
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
2046
2060
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
2047
- if (delta === 0) {
2048
- return;
2049
- }
2050
2061
 
2051
2062
  // Support RTL layouts
2052
2063
  const isHorizontal = direction === "horizontal";
@@ -2199,8 +2210,9 @@ function PanelGroupWithForwardedRef({
2199
2210
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2200
2211
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2201
2212
  eagerValuesRef.current.panelDataArrayChanged = true;
2213
+ forceUpdate();
2202
2214
  }
2203
- }, []);
2215
+ }, [forceUpdate]);
2204
2216
  const context = useMemo(() => ({
2205
2217
  collapsePanel,
2206
2218
  direction,
@@ -481,6 +481,13 @@ function handlePointerMove(event) {
481
481
  x,
482
482
  y
483
483
  } = getResizeEventCoordinates(event);
484
+
485
+ // Edge case (see #340)
486
+ // Detect when the pointer has been released outside an iframe on a different domain
487
+ if (event.buttons === 0) {
488
+ isPointerDown = false;
489
+ updateResizeHandlerStates("up", event);
490
+ }
484
491
  if (!isPointerDown) {
485
492
  const {
486
493
  target
@@ -669,6 +676,11 @@ function updateResizeHandlerStates(action, event) {
669
676
  });
670
677
  }
671
678
 
679
+ function useForceUpdate() {
680
+ const [_, setCount] = useState(0);
681
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
682
+ }
683
+
672
684
  function assert(expectedCondition, message) {
673
685
  if (!expectedCondition) {
674
686
  console.error(message);
@@ -1636,6 +1648,7 @@ function PanelGroupWithForwardedRef({
1636
1648
  const panelGroupElementRef = useRef(null);
1637
1649
  const [dragState, setDragState] = useState(null);
1638
1650
  const [layout, setLayout] = useState([]);
1651
+ const forceUpdate = useForceUpdate();
1639
1652
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1640
1653
  const panelSizeBeforeCollapseRef = useRef(new Map());
1641
1654
  const prevDeltaRef = useRef(0);
@@ -1940,7 +1953,8 @@ function PanelGroupWithForwardedRef({
1940
1953
  }
1941
1954
  });
1942
1955
  eagerValuesRef.current.panelDataArrayChanged = true;
1943
- }, []);
1956
+ forceUpdate();
1957
+ }, [forceUpdate]);
1944
1958
 
1945
1959
  // (Re)calculate group layout whenever panels are registered or unregistered.
1946
1960
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2020,9 +2034,6 @@ function PanelGroupWithForwardedRef({
2020
2034
  } = dragState !== null && dragState !== void 0 ? dragState : {};
2021
2035
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
2022
2036
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
2023
- if (delta === 0) {
2024
- return;
2025
- }
2026
2037
 
2027
2038
  // Support RTL layouts
2028
2039
  const isHorizontal = direction === "horizontal";
@@ -2175,8 +2186,9 @@ function PanelGroupWithForwardedRef({
2175
2186
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2176
2187
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2177
2188
  eagerValuesRef.current.panelDataArrayChanged = true;
2189
+ forceUpdate();
2178
2190
  }
2179
- }, []);
2191
+ }, [forceUpdate]);
2180
2192
  const context = useMemo(() => ({
2181
2193
  collapsePanel,
2182
2194
  direction,
@@ -467,6 +467,13 @@ function handlePointerMove(event) {
467
467
  x,
468
468
  y
469
469
  } = getResizeEventCoordinates(event);
470
+
471
+ // Edge case (see #340)
472
+ // Detect when the pointer has been released outside an iframe on a different domain
473
+ if (event.buttons === 0) {
474
+ isPointerDown = false;
475
+ updateResizeHandlerStates("up", event);
476
+ }
470
477
  if (!isPointerDown) {
471
478
  const {
472
479
  target
@@ -655,6 +662,11 @@ function updateResizeHandlerStates(action, event) {
655
662
  });
656
663
  }
657
664
 
665
+ function useForceUpdate() {
666
+ const [_, setCount] = useState(0);
667
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
668
+ }
669
+
658
670
  function assert(expectedCondition, message) {
659
671
  if (!expectedCondition) {
660
672
  console.error(message);
@@ -1492,6 +1504,7 @@ function PanelGroupWithForwardedRef({
1492
1504
  const panelGroupElementRef = useRef(null);
1493
1505
  const [dragState, setDragState] = useState(null);
1494
1506
  const [layout, setLayout] = useState([]);
1507
+ const forceUpdate = useForceUpdate();
1495
1508
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1496
1509
  const panelSizeBeforeCollapseRef = useRef(new Map());
1497
1510
  const prevDeltaRef = useRef(0);
@@ -1788,7 +1801,8 @@ function PanelGroupWithForwardedRef({
1788
1801
  }
1789
1802
  });
1790
1803
  eagerValuesRef.current.panelDataArrayChanged = true;
1791
- }, []);
1804
+ forceUpdate();
1805
+ }, [forceUpdate]);
1792
1806
  const registerResizeHandle = useCallback(dragHandleId => {
1793
1807
  return function resizeHandler(event) {
1794
1808
  event.preventDefault();
@@ -1812,9 +1826,6 @@ function PanelGroupWithForwardedRef({
1812
1826
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1813
1827
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1814
1828
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1815
- if (delta === 0) {
1816
- return;
1817
- }
1818
1829
 
1819
1830
  // Support RTL layouts
1820
1831
  const isHorizontal = direction === "horizontal";
@@ -1967,8 +1978,9 @@ function PanelGroupWithForwardedRef({
1967
1978
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
1968
1979
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
1969
1980
  eagerValuesRef.current.panelDataArrayChanged = true;
1981
+ forceUpdate();
1970
1982
  }
1971
- }, []);
1983
+ }, [forceUpdate]);
1972
1984
  const context = useMemo(() => ({
1973
1985
  collapsePanel,
1974
1986
  direction,
@@ -443,6 +443,13 @@ function handlePointerMove(event) {
443
443
  x,
444
444
  y
445
445
  } = getResizeEventCoordinates(event);
446
+
447
+ // Edge case (see #340)
448
+ // Detect when the pointer has been released outside an iframe on a different domain
449
+ if (event.buttons === 0) {
450
+ isPointerDown = false;
451
+ updateResizeHandlerStates("up", event);
452
+ }
446
453
  if (!isPointerDown) {
447
454
  const {
448
455
  target
@@ -631,6 +638,11 @@ function updateResizeHandlerStates(action, event) {
631
638
  });
632
639
  }
633
640
 
641
+ function useForceUpdate() {
642
+ const [_, setCount] = useState(0);
643
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
644
+ }
645
+
634
646
  function assert(expectedCondition, message) {
635
647
  if (!expectedCondition) {
636
648
  console.error(message);
@@ -1468,6 +1480,7 @@ function PanelGroupWithForwardedRef({
1468
1480
  const panelGroupElementRef = useRef(null);
1469
1481
  const [dragState, setDragState] = useState(null);
1470
1482
  const [layout, setLayout] = useState([]);
1483
+ const forceUpdate = useForceUpdate();
1471
1484
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1472
1485
  const panelSizeBeforeCollapseRef = useRef(new Map());
1473
1486
  const prevDeltaRef = useRef(0);
@@ -1764,7 +1777,8 @@ function PanelGroupWithForwardedRef({
1764
1777
  }
1765
1778
  });
1766
1779
  eagerValuesRef.current.panelDataArrayChanged = true;
1767
- }, []);
1780
+ forceUpdate();
1781
+ }, [forceUpdate]);
1768
1782
  const registerResizeHandle = useCallback(dragHandleId => {
1769
1783
  return function resizeHandler(event) {
1770
1784
  event.preventDefault();
@@ -1788,9 +1802,6 @@ function PanelGroupWithForwardedRef({
1788
1802
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1789
1803
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1790
1804
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1791
- if (delta === 0) {
1792
- return;
1793
- }
1794
1805
 
1795
1806
  // Support RTL layouts
1796
1807
  const isHorizontal = direction === "horizontal";
@@ -1943,8 +1954,9 @@ function PanelGroupWithForwardedRef({
1943
1954
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
1944
1955
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
1945
1956
  eagerValuesRef.current.panelDataArrayChanged = true;
1957
+ forceUpdate();
1946
1958
  }
1947
- }, []);
1959
+ }, [forceUpdate]);
1948
1960
  const context = useMemo(() => ({
1949
1961
  collapsePanel,
1950
1962
  direction,
@@ -470,6 +470,13 @@ function handlePointerMove(event) {
470
470
  x,
471
471
  y
472
472
  } = getResizeEventCoordinates(event);
473
+
474
+ // Edge case (see #340)
475
+ // Detect when the pointer has been released outside an iframe on a different domain
476
+ if (event.buttons === 0) {
477
+ isPointerDown = false;
478
+ updateResizeHandlerStates("up", event);
479
+ }
473
480
  if (!isPointerDown) {
474
481
  const {
475
482
  target
@@ -658,6 +665,11 @@ function updateResizeHandlerStates(action, event) {
658
665
  });
659
666
  }
660
667
 
668
+ function useForceUpdate() {
669
+ const [_, setCount] = useState(0);
670
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
671
+ }
672
+
661
673
  function assert(expectedCondition, message) {
662
674
  if (!expectedCondition) {
663
675
  console.error(message);
@@ -1567,6 +1579,7 @@ function PanelGroupWithForwardedRef({
1567
1579
  const panelGroupElementRef = useRef(null);
1568
1580
  const [dragState, setDragState] = useState(null);
1569
1581
  const [layout, setLayout] = useState([]);
1582
+ const forceUpdate = useForceUpdate();
1570
1583
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1571
1584
  const panelSizeBeforeCollapseRef = useRef(new Map());
1572
1585
  const prevDeltaRef = useRef(0);
@@ -1829,7 +1842,8 @@ function PanelGroupWithForwardedRef({
1829
1842
  }
1830
1843
  });
1831
1844
  eagerValuesRef.current.panelDataArrayChanged = true;
1832
- }, []);
1845
+ forceUpdate();
1846
+ }, [forceUpdate]);
1833
1847
 
1834
1848
  // (Re)calculate group layout whenever panels are registered or unregistered.
1835
1849
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1909,9 +1923,6 @@ function PanelGroupWithForwardedRef({
1909
1923
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1910
1924
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1911
1925
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1912
- if (delta === 0) {
1913
- return;
1914
- }
1915
1926
 
1916
1927
  // Support RTL layouts
1917
1928
  const isHorizontal = direction === "horizontal";
@@ -2064,8 +2075,9 @@ function PanelGroupWithForwardedRef({
2064
2075
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
2065
2076
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
2066
2077
  eagerValuesRef.current.panelDataArrayChanged = true;
2078
+ forceUpdate();
2067
2079
  }
2068
- }, []);
2080
+ }, [forceUpdate]);
2069
2081
  const context = useMemo(() => ({
2070
2082
  collapsePanel,
2071
2083
  direction,
@@ -456,6 +456,13 @@ function handlePointerMove(event) {
456
456
  x,
457
457
  y
458
458
  } = getResizeEventCoordinates(event);
459
+
460
+ // Edge case (see #340)
461
+ // Detect when the pointer has been released outside an iframe on a different domain
462
+ if (event.buttons === 0) {
463
+ isPointerDown = false;
464
+ updateResizeHandlerStates("up", event);
465
+ }
459
466
  if (!isPointerDown) {
460
467
  const {
461
468
  target
@@ -644,6 +651,11 @@ function updateResizeHandlerStates(action, event) {
644
651
  });
645
652
  }
646
653
 
654
+ function useForceUpdate() {
655
+ const [_, setCount] = useState(0);
656
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
657
+ }
658
+
647
659
  function assert(expectedCondition, message) {
648
660
  if (!expectedCondition) {
649
661
  console.error(message);
@@ -1433,6 +1445,7 @@ function PanelGroupWithForwardedRef({
1433
1445
  const panelGroupElementRef = useRef(null);
1434
1446
  const [dragState, setDragState] = useState(null);
1435
1447
  const [layout, setLayout] = useState([]);
1448
+ const forceUpdate = useForceUpdate();
1436
1449
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1437
1450
  const panelSizeBeforeCollapseRef = useRef(new Map());
1438
1451
  const prevDeltaRef = useRef(0);
@@ -1687,7 +1700,8 @@ function PanelGroupWithForwardedRef({
1687
1700
  }
1688
1701
  });
1689
1702
  eagerValuesRef.current.panelDataArrayChanged = true;
1690
- }, []);
1703
+ forceUpdate();
1704
+ }, [forceUpdate]);
1691
1705
  const registerResizeHandle = useCallback(dragHandleId => {
1692
1706
  return function resizeHandler(event) {
1693
1707
  event.preventDefault();
@@ -1711,9 +1725,6 @@ function PanelGroupWithForwardedRef({
1711
1725
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1712
1726
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1713
1727
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1714
- if (delta === 0) {
1715
- return;
1716
- }
1717
1728
 
1718
1729
  // Support RTL layouts
1719
1730
  const isHorizontal = direction === "horizontal";
@@ -1866,8 +1877,9 @@ function PanelGroupWithForwardedRef({
1866
1877
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
1867
1878
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
1868
1879
  eagerValuesRef.current.panelDataArrayChanged = true;
1880
+ forceUpdate();
1869
1881
  }
1870
- }, []);
1882
+ }, [forceUpdate]);
1871
1883
  const context = useMemo(() => ({
1872
1884
  collapsePanel,
1873
1885
  direction,
@@ -432,6 +432,13 @@ function handlePointerMove(event) {
432
432
  x,
433
433
  y
434
434
  } = getResizeEventCoordinates(event);
435
+
436
+ // Edge case (see #340)
437
+ // Detect when the pointer has been released outside an iframe on a different domain
438
+ if (event.buttons === 0) {
439
+ isPointerDown = false;
440
+ updateResizeHandlerStates("up", event);
441
+ }
435
442
  if (!isPointerDown) {
436
443
  const {
437
444
  target
@@ -620,6 +627,11 @@ function updateResizeHandlerStates(action, event) {
620
627
  });
621
628
  }
622
629
 
630
+ function useForceUpdate() {
631
+ const [_, setCount] = useState(0);
632
+ return useCallback(() => setCount(prevCount => prevCount + 1), []);
633
+ }
634
+
623
635
  function assert(expectedCondition, message) {
624
636
  if (!expectedCondition) {
625
637
  console.error(message);
@@ -1409,6 +1421,7 @@ function PanelGroupWithForwardedRef({
1409
1421
  const panelGroupElementRef = useRef(null);
1410
1422
  const [dragState, setDragState] = useState(null);
1411
1423
  const [layout, setLayout] = useState([]);
1424
+ const forceUpdate = useForceUpdate();
1412
1425
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1413
1426
  const panelSizeBeforeCollapseRef = useRef(new Map());
1414
1427
  const prevDeltaRef = useRef(0);
@@ -1663,7 +1676,8 @@ function PanelGroupWithForwardedRef({
1663
1676
  }
1664
1677
  });
1665
1678
  eagerValuesRef.current.panelDataArrayChanged = true;
1666
- }, []);
1679
+ forceUpdate();
1680
+ }, [forceUpdate]);
1667
1681
  const registerResizeHandle = useCallback(dragHandleId => {
1668
1682
  return function resizeHandler(event) {
1669
1683
  event.preventDefault();
@@ -1687,9 +1701,6 @@ function PanelGroupWithForwardedRef({
1687
1701
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1688
1702
  const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
1689
1703
  let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
1690
- if (delta === 0) {
1691
- return;
1692
- }
1693
1704
 
1694
1705
  // Support RTL layouts
1695
1706
  const isHorizontal = direction === "horizontal";
@@ -1842,8 +1853,9 @@ function PanelGroupWithForwardedRef({
1842
1853
  // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
1843
1854
  delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
1844
1855
  eagerValuesRef.current.panelDataArrayChanged = true;
1856
+ forceUpdate();
1845
1857
  }
1846
- }, []);
1858
+ }, [forceUpdate]);
1847
1859
  const context = useMemo(() => ({
1848
1860
  collapsePanel,
1849
1861
  direction,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-resizable-panels",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
4
4
  "description": "React components for resizable panel groups/layouts",
5
5
  "author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
6
6
  "license": "MIT",
package/src/PanelGroup.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  EXCEEDED_VERTICAL_MIN,
14
14
  reportConstraintsViolation,
15
15
  } from "./PanelResizeHandleRegistry";
16
+ import { useForceUpdate } from "./hooks/useForceUpdate";
16
17
  import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
17
18
  import useUniqueId from "./hooks/useUniqueId";
18
19
  import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterPanelGroupBehavior";
@@ -123,6 +124,7 @@ function PanelGroupWithForwardedRef({
123
124
  const panelGroupElementRef = useRef<HTMLDivElement | null>(null);
124
125
  const [dragState, setDragState] = useState<DragState | null>(null);
125
126
  const [layout, setLayout] = useState<number[]>([]);
127
+ const forceUpdate = useForceUpdate();
126
128
 
127
129
  const panelIdToLastNotifiedSizeMapRef = useRef<Record<string, number>>({});
128
130
  const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
@@ -521,26 +523,31 @@ function PanelGroupWithForwardedRef({
521
523
  return !collapsible || fuzzyCompareNumbers(panelSize, collapsedSize) > 0;
522
524
  }, []);
523
525
 
524
- const registerPanel = useCallback((panelData: PanelData) => {
525
- const { panelDataArray } = eagerValuesRef.current;
526
+ const registerPanel = useCallback(
527
+ (panelData: PanelData) => {
528
+ const { panelDataArray } = eagerValuesRef.current;
526
529
 
527
- panelDataArray.push(panelData);
528
- panelDataArray.sort((panelA, panelB) => {
529
- const orderA = panelA.order;
530
- const orderB = panelB.order;
531
- if (orderA == null && orderB == null) {
532
- return 0;
533
- } else if (orderA == null) {
534
- return -1;
535
- } else if (orderB == null) {
536
- return 1;
537
- } else {
538
- return orderA - orderB;
539
- }
540
- });
530
+ panelDataArray.push(panelData);
531
+ panelDataArray.sort((panelA, panelB) => {
532
+ const orderA = panelA.order;
533
+ const orderB = panelB.order;
534
+ if (orderA == null && orderB == null) {
535
+ return 0;
536
+ } else if (orderA == null) {
537
+ return -1;
538
+ } else if (orderB == null) {
539
+ return 1;
540
+ } else {
541
+ return orderA - orderB;
542
+ }
543
+ });
541
544
 
542
- eagerValuesRef.current.panelDataArrayChanged = true;
543
- }, []);
545
+ eagerValuesRef.current.panelDataArrayChanged = true;
546
+
547
+ forceUpdate();
548
+ },
549
+ [forceUpdate]
550
+ );
544
551
 
545
552
  // (Re)calculate group layout whenever panels are registered or unregistered.
546
553
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -638,9 +645,6 @@ function PanelGroupWithForwardedRef({
638
645
  keyboardResizeBy,
639
646
  panelGroupElement
640
647
  );
641
- if (delta === 0) {
642
- return;
643
- }
644
648
 
645
649
  // Support RTL layouts
646
650
  const isHorizontal = direction === "horizontal";
@@ -847,22 +851,27 @@ function PanelGroupWithForwardedRef({
847
851
  setDragState(null);
848
852
  }, []);
849
853
 
850
- const unregisterPanel = useCallback((panelData: PanelData) => {
851
- const { panelDataArray } = eagerValuesRef.current;
854
+ const unregisterPanel = useCallback(
855
+ (panelData: PanelData) => {
856
+ const { panelDataArray } = eagerValuesRef.current;
852
857
 
853
- const index = findPanelDataIndex(panelDataArray, panelData);
854
- if (index >= 0) {
855
- panelDataArray.splice(index, 1);
858
+ const index = findPanelDataIndex(panelDataArray, panelData);
859
+ if (index >= 0) {
860
+ panelDataArray.splice(index, 1);
856
861
 
857
- // TRICKY
858
- // When a panel is removed from the group, we should delete the most recent prev-size entry for it.
859
- // If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
860
- // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
861
- delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
862
+ // TRICKY
863
+ // When a panel is removed from the group, we should delete the most recent prev-size entry for it.
864
+ // If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
865
+ // Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
866
+ delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
862
867
 
863
- eagerValuesRef.current.panelDataArrayChanged = true;
864
- }
865
- }, []);
868
+ eagerValuesRef.current.panelDataArrayChanged = true;
869
+
870
+ forceUpdate();
871
+ }
872
+ },
873
+ [forceUpdate]
874
+ );
866
875
 
867
876
  const context = useMemo(
868
877
  () =>
@@ -87,7 +87,7 @@ export function registerResizeHandle(
87
87
  };
88
88
  }
89
89
 
90
- function handlePointerDown(event: ResizeEvent) {
90
+ function handlePointerDown(event: PointerEvent) {
91
91
  const { target } = event;
92
92
  const { x, y } = getResizeEventCoordinates(event);
93
93
 
@@ -104,9 +104,17 @@ function handlePointerDown(event: ResizeEvent) {
104
104
  }
105
105
  }
106
106
 
107
- function handlePointerMove(event: ResizeEvent) {
107
+ function handlePointerMove(event: PointerEvent) {
108
108
  const { x, y } = getResizeEventCoordinates(event);
109
109
 
110
+ // Edge case (see #340)
111
+ // Detect when the pointer has been released outside an iframe on a different domain
112
+ if (event.buttons === 0) {
113
+ isPointerDown = false;
114
+
115
+ updateResizeHandlerStates("up", event);
116
+ }
117
+
110
118
  if (!isPointerDown) {
111
119
  const { target } = event;
112
120
 
@@ -0,0 +1,7 @@
1
+ import { useCallback, useState } from "../vendor/react";
2
+
3
+ export function useForceUpdate() {
4
+ const [_, setCount] = useState(0);
5
+
6
+ return useCallback(() => setCount((prevCount) => prevCount + 1), []);
7
+ }
@@ -12,6 +12,7 @@ export function dispatchPointerEvent(type: string, target: HTMLElement) {
12
12
  bubbles: true,
13
13
  clientX,
14
14
  clientY,
15
+ buttons: 1,
15
16
  });
16
17
  Object.defineProperties(event, {
17
18
  pageX: {