react-resizable-panels 2.0.2 → 2.0.4

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.
@@ -330,24 +330,19 @@ function handlePointerMove(event) {
330
330
  x,
331
331
  y
332
332
  } = getResizeEventCoordinates(event);
333
- if (isPointerDown) {
334
- intersectingHandles.forEach(data => {
335
- const {
336
- setResizeHandlerState
337
- } = data;
338
- setResizeHandlerState("move", "drag", event);
339
- });
340
-
341
- // Update cursor based on return value(s) from active handles
342
- updateCursor();
343
- } else {
333
+ if (!isPointerDown) {
334
+ // Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
335
+ // at that point, the handles may not move with the pointer (depending on constraints)
336
+ // but the same set of active handles should be locked until the pointer is released
344
337
  recalculateIntersectingHandles({
345
338
  x,
346
339
  y
347
340
  });
348
- updateResizeHandlerStates("move", event);
349
- updateCursor();
350
341
  }
342
+ updateResizeHandlerStates("move", event);
343
+
344
+ // Update cursor based on return value(s) from active handles
345
+ updateCursor();
351
346
  if (intersectingHandles.length > 0) {
352
347
  event.preventDefault();
353
348
  }
@@ -480,15 +475,8 @@ function updateResizeHandlerStates(action, event) {
480
475
  const {
481
476
  setResizeHandlerState
482
477
  } = data;
483
- if (intersectingHandles.includes(data)) {
484
- if (isPointerDown) {
485
- setResizeHandlerState(action, "drag", event);
486
- } else {
487
- setResizeHandlerState(action, "hover", event);
488
- }
489
- } else {
490
- setResizeHandlerState(action, "inactive", event);
491
- }
478
+ const isActive = intersectingHandles.includes(data);
479
+ setResizeHandlerState(action, isActive, event);
492
480
  });
493
481
  }
494
482
 
@@ -2025,6 +2013,12 @@ function PanelResizeHandle({
2025
2013
  const [state, setState] = useState("inactive");
2026
2014
  const [isFocused, setIsFocused] = useState(false);
2027
2015
  const [resizeHandler, setResizeHandler] = useState(null);
2016
+ const committedValuesRef = useRef({
2017
+ state
2018
+ });
2019
+ useLayoutEffect(() => {
2020
+ committedValuesRef.current.state = state;
2021
+ });
2028
2022
  useEffect(() => {
2029
2023
  if (disabled) {
2030
2024
  setResizeHandler(null);
@@ -2040,26 +2034,47 @@ function PanelResizeHandle({
2040
2034
  }
2041
2035
  const element = elementRef.current;
2042
2036
  assert(element);
2043
- const setResizeHandlerState = (action, state, event) => {
2044
- setState(state);
2045
- switch (action) {
2046
- case "down":
2047
- {
2048
- startDragging(resizeHandleId, event);
2049
- break;
2050
- }
2051
- case "up":
2052
- {
2053
- stopDragging();
2054
- break;
2055
- }
2056
- }
2057
- switch (state) {
2058
- case "drag":
2059
- {
2060
- resizeHandler(event);
2061
- break;
2062
- }
2037
+ const setResizeHandlerState = (action, isActive, event) => {
2038
+ if (isActive) {
2039
+ switch (action) {
2040
+ case "down":
2041
+ {
2042
+ setState("drag");
2043
+ startDragging(resizeHandleId, event);
2044
+ const {
2045
+ onDragging
2046
+ } = callbacksRef.current;
2047
+ if (onDragging) {
2048
+ onDragging(true);
2049
+ }
2050
+ break;
2051
+ }
2052
+ case "move":
2053
+ {
2054
+ const {
2055
+ state
2056
+ } = committedValuesRef.current;
2057
+ if (state !== "drag") {
2058
+ setState("hover");
2059
+ }
2060
+ resizeHandler(event);
2061
+ break;
2062
+ }
2063
+ case "up":
2064
+ {
2065
+ setState("hover");
2066
+ stopDragging();
2067
+ const {
2068
+ onDragging
2069
+ } = callbacksRef.current;
2070
+ if (onDragging) {
2071
+ onDragging(false);
2072
+ }
2073
+ break;
2074
+ }
2075
+ }
2076
+ } else {
2077
+ setState("inactive");
2063
2078
  }
2064
2079
  };
2065
2080
  return registerResizeHandle(resizeHandleId, element, direction, {
@@ -317,24 +317,19 @@ function handlePointerMove(event) {
317
317
  x,
318
318
  y
319
319
  } = getResizeEventCoordinates(event);
320
- if (isPointerDown) {
321
- intersectingHandles.forEach(data => {
322
- const {
323
- setResizeHandlerState
324
- } = data;
325
- setResizeHandlerState("move", "drag", event);
326
- });
327
-
328
- // Update cursor based on return value(s) from active handles
329
- updateCursor();
330
- } else {
320
+ if (!isPointerDown) {
321
+ // Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
322
+ // at that point, the handles may not move with the pointer (depending on constraints)
323
+ // but the same set of active handles should be locked until the pointer is released
331
324
  recalculateIntersectingHandles({
332
325
  x,
333
326
  y
334
327
  });
335
- updateResizeHandlerStates("move", event);
336
- updateCursor();
337
328
  }
329
+ updateResizeHandlerStates("move", event);
330
+
331
+ // Update cursor based on return value(s) from active handles
332
+ updateCursor();
338
333
  if (intersectingHandles.length > 0) {
339
334
  event.preventDefault();
340
335
  }
@@ -467,15 +462,8 @@ function updateResizeHandlerStates(action, event) {
467
462
  const {
468
463
  setResizeHandlerState
469
464
  } = data;
470
- if (intersectingHandles.includes(data)) {
471
- if (isPointerDown) {
472
- setResizeHandlerState(action, "drag", event);
473
- } else {
474
- setResizeHandlerState(action, "hover", event);
475
- }
476
- } else {
477
- setResizeHandlerState(action, "inactive", event);
478
- }
465
+ const isActive = intersectingHandles.includes(data);
466
+ setResizeHandlerState(action, isActive, event);
479
467
  });
480
468
  }
481
469
 
@@ -1828,6 +1816,12 @@ function PanelResizeHandle({
1828
1816
  const [state, setState] = useState("inactive");
1829
1817
  const [isFocused, setIsFocused] = useState(false);
1830
1818
  const [resizeHandler, setResizeHandler] = useState(null);
1819
+ const committedValuesRef = useRef({
1820
+ state
1821
+ });
1822
+ useLayoutEffect(() => {
1823
+ committedValuesRef.current.state = state;
1824
+ });
1831
1825
  useEffect(() => {
1832
1826
  if (disabled) {
1833
1827
  setResizeHandler(null);
@@ -1843,26 +1837,47 @@ function PanelResizeHandle({
1843
1837
  }
1844
1838
  const element = elementRef.current;
1845
1839
  assert(element);
1846
- const setResizeHandlerState = (action, state, event) => {
1847
- setState(state);
1848
- switch (action) {
1849
- case "down":
1850
- {
1851
- startDragging(resizeHandleId, event);
1852
- break;
1853
- }
1854
- case "up":
1855
- {
1856
- stopDragging();
1857
- break;
1858
- }
1859
- }
1860
- switch (state) {
1861
- case "drag":
1862
- {
1863
- resizeHandler(event);
1864
- break;
1865
- }
1840
+ const setResizeHandlerState = (action, isActive, event) => {
1841
+ if (isActive) {
1842
+ switch (action) {
1843
+ case "down":
1844
+ {
1845
+ setState("drag");
1846
+ startDragging(resizeHandleId, event);
1847
+ const {
1848
+ onDragging
1849
+ } = callbacksRef.current;
1850
+ if (onDragging) {
1851
+ onDragging(true);
1852
+ }
1853
+ break;
1854
+ }
1855
+ case "move":
1856
+ {
1857
+ const {
1858
+ state
1859
+ } = committedValuesRef.current;
1860
+ if (state !== "drag") {
1861
+ setState("hover");
1862
+ }
1863
+ resizeHandler(event);
1864
+ break;
1865
+ }
1866
+ case "up":
1867
+ {
1868
+ setState("hover");
1869
+ stopDragging();
1870
+ const {
1871
+ onDragging
1872
+ } = callbacksRef.current;
1873
+ if (onDragging) {
1874
+ onDragging(false);
1875
+ }
1876
+ break;
1877
+ }
1878
+ }
1879
+ } else {
1880
+ setState("inactive");
1866
1881
  }
1867
1882
  };
1868
1883
  return registerResizeHandle(resizeHandleId, element, direction, {
@@ -293,24 +293,19 @@ function handlePointerMove(event) {
293
293
  x,
294
294
  y
295
295
  } = getResizeEventCoordinates(event);
296
- if (isPointerDown) {
297
- intersectingHandles.forEach(data => {
298
- const {
299
- setResizeHandlerState
300
- } = data;
301
- setResizeHandlerState("move", "drag", event);
302
- });
303
-
304
- // Update cursor based on return value(s) from active handles
305
- updateCursor();
306
- } else {
296
+ if (!isPointerDown) {
297
+ // Recalculate intersecting handles whenever the pointer moves, except if it has already been pressed
298
+ // at that point, the handles may not move with the pointer (depending on constraints)
299
+ // but the same set of active handles should be locked until the pointer is released
307
300
  recalculateIntersectingHandles({
308
301
  x,
309
302
  y
310
303
  });
311
- updateResizeHandlerStates("move", event);
312
- updateCursor();
313
304
  }
305
+ updateResizeHandlerStates("move", event);
306
+
307
+ // Update cursor based on return value(s) from active handles
308
+ updateCursor();
314
309
  if (intersectingHandles.length > 0) {
315
310
  event.preventDefault();
316
311
  }
@@ -443,15 +438,8 @@ function updateResizeHandlerStates(action, event) {
443
438
  const {
444
439
  setResizeHandlerState
445
440
  } = data;
446
- if (intersectingHandles.includes(data)) {
447
- if (isPointerDown) {
448
- setResizeHandlerState(action, "drag", event);
449
- } else {
450
- setResizeHandlerState(action, "hover", event);
451
- }
452
- } else {
453
- setResizeHandlerState(action, "inactive", event);
454
- }
441
+ const isActive = intersectingHandles.includes(data);
442
+ setResizeHandlerState(action, isActive, event);
455
443
  });
456
444
  }
457
445
 
@@ -1804,6 +1792,12 @@ function PanelResizeHandle({
1804
1792
  const [state, setState] = useState("inactive");
1805
1793
  const [isFocused, setIsFocused] = useState(false);
1806
1794
  const [resizeHandler, setResizeHandler] = useState(null);
1795
+ const committedValuesRef = useRef({
1796
+ state
1797
+ });
1798
+ useLayoutEffect(() => {
1799
+ committedValuesRef.current.state = state;
1800
+ });
1807
1801
  useEffect(() => {
1808
1802
  if (disabled) {
1809
1803
  setResizeHandler(null);
@@ -1819,26 +1813,47 @@ function PanelResizeHandle({
1819
1813
  }
1820
1814
  const element = elementRef.current;
1821
1815
  assert(element);
1822
- const setResizeHandlerState = (action, state, event) => {
1823
- setState(state);
1824
- switch (action) {
1825
- case "down":
1826
- {
1827
- startDragging(resizeHandleId, event);
1828
- break;
1829
- }
1830
- case "up":
1831
- {
1832
- stopDragging();
1833
- break;
1834
- }
1835
- }
1836
- switch (state) {
1837
- case "drag":
1838
- {
1839
- resizeHandler(event);
1840
- break;
1841
- }
1816
+ const setResizeHandlerState = (action, isActive, event) => {
1817
+ if (isActive) {
1818
+ switch (action) {
1819
+ case "down":
1820
+ {
1821
+ setState("drag");
1822
+ startDragging(resizeHandleId, event);
1823
+ const {
1824
+ onDragging
1825
+ } = callbacksRef.current;
1826
+ if (onDragging) {
1827
+ onDragging(true);
1828
+ }
1829
+ break;
1830
+ }
1831
+ case "move":
1832
+ {
1833
+ const {
1834
+ state
1835
+ } = committedValuesRef.current;
1836
+ if (state !== "drag") {
1837
+ setState("hover");
1838
+ }
1839
+ resizeHandler(event);
1840
+ break;
1841
+ }
1842
+ case "up":
1843
+ {
1844
+ setState("hover");
1845
+ stopDragging();
1846
+ const {
1847
+ onDragging
1848
+ } = callbacksRef.current;
1849
+ if (onDragging) {
1850
+ onDragging(false);
1851
+ }
1852
+ break;
1853
+ }
1854
+ }
1855
+ } else {
1856
+ setState("inactive");
1842
1857
  }
1843
1858
  };
1844
1859
  return registerResizeHandle(resizeHandleId, element, direction, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-resizable-panels",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "React components for resizable panel groups/layouts",
5
5
  "author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
6
6
  "license": "MIT",
@@ -72,6 +72,8 @@
72
72
  "eslint": "^8.37.0",
73
73
  "eslint-plugin-no-restricted-imports": "^0.0.0",
74
74
  "eslint-plugin-react-hooks": "^4.6.0",
75
+ "jest": "^29.7.0",
76
+ "jest-environment-jsdom": "^29.7.0",
75
77
  "react": "experimental",
76
78
  "react-dom": "experimental"
77
79
  },
@@ -5,6 +5,7 @@ import { assert } from "./utils/assert";
5
5
  import { getPanelElement } from "./utils/dom/getPanelElement";
6
6
  import {
7
7
  mockPanelGroupOffsetWidthAndHeight,
8
+ verifyAttribute,
8
9
  verifyExpandedPanelGroupLayout,
9
10
  } from "./utils/test-utils";
10
11
  import { createRef } from "./vendor/react";
@@ -675,6 +676,68 @@ describe("PanelGroup", () => {
675
676
  });
676
677
  });
677
678
 
679
+ describe("data attributes", () => {
680
+ it("should initialize with the correct props based attributes", () => {
681
+ act(() => {
682
+ root.render(
683
+ <PanelGroup direction="horizontal" id="test-group">
684
+ <Panel defaultSize={75} id="left-panel" />
685
+ <PanelResizeHandle />
686
+ <Panel collapsible id="right-panel" />
687
+ </PanelGroup>
688
+ );
689
+ });
690
+
691
+ const leftElement = getPanelElement("left-panel", container);
692
+ const rightElement = getPanelElement("right-panel", container);
693
+
694
+ assert(leftElement);
695
+ assert(rightElement);
696
+
697
+ verifyAttribute(leftElement, "data-panel", "");
698
+ verifyAttribute(leftElement, "data-panel-id", "left-panel");
699
+ verifyAttribute(leftElement, "data-panel-group-id", "test-group");
700
+ verifyAttribute(leftElement, "data-panel-size", "75.0");
701
+ verifyAttribute(leftElement, "data-panel-collapsible", null);
702
+
703
+ verifyAttribute(rightElement, "data-panel", "");
704
+ verifyAttribute(rightElement, "data-panel-id", "right-panel");
705
+ verifyAttribute(rightElement, "data-panel-group-id", "test-group");
706
+ verifyAttribute(rightElement, "data-panel-size", "25.0");
707
+ verifyAttribute(rightElement, "data-panel-collapsible", "true");
708
+ });
709
+
710
+ it("should update the data-panel-size attribute when the panel resizes", () => {
711
+ const leftPanelRef = createRef<ImperativePanelHandle>();
712
+
713
+ act(() => {
714
+ root.render(
715
+ <PanelGroup direction="horizontal" id="test-group">
716
+ <Panel defaultSize={75} id="left-panel" ref={leftPanelRef} />
717
+ <PanelResizeHandle />
718
+ <Panel collapsible id="right-panel" />
719
+ </PanelGroup>
720
+ );
721
+ });
722
+
723
+ const leftElement = getPanelElement("left-panel", container);
724
+ const rightElement = getPanelElement("right-panel", container);
725
+
726
+ assert(leftElement);
727
+ assert(rightElement);
728
+
729
+ verifyAttribute(leftElement, "data-panel-size", "75.0");
730
+ verifyAttribute(rightElement, "data-panel-size", "25.0");
731
+
732
+ act(() => {
733
+ leftPanelRef.current?.resize(30);
734
+ });
735
+
736
+ verifyAttribute(leftElement, "data-panel-size", "30.0");
737
+ verifyAttribute(rightElement, "data-panel-size", "70.0");
738
+ });
739
+ });
740
+
678
741
  describe("DEV warnings", () => {
679
742
  it("should warn about server rendered panels with no default size", () => {
680
743
  jest.resetModules();
@@ -13,7 +13,10 @@ import {
13
13
  } from ".";
14
14
  import { assert } from "./utils/assert";
15
15
  import { getPanelGroupElement } from "./utils/dom/getPanelGroupElement";
16
- import { mockPanelGroupOffsetWidthAndHeight } from "./utils/test-utils";
16
+ import {
17
+ mockPanelGroupOffsetWidthAndHeight,
18
+ verifyAttribute,
19
+ } from "./utils/test-utils";
17
20
  import { createRef } from "./vendor/react";
18
21
 
19
22
  describe("PanelGroup", () => {
@@ -256,6 +259,23 @@ describe("PanelGroup", () => {
256
259
  });
257
260
  });
258
261
 
262
+ describe("data attributes", () => {
263
+ it("should initialize with the correct props based attributes", () => {
264
+ act(() => {
265
+ root.render(
266
+ <PanelGroup direction="horizontal" id="test-group"></PanelGroup>
267
+ );
268
+ });
269
+
270
+ const element = getPanelGroupElement("test-group", container);
271
+ assert(element);
272
+
273
+ verifyAttribute(element, "data-panel-group", "");
274
+ verifyAttribute(element, "data-panel-group-direction", "horizontal");
275
+ verifyAttribute(element, "data-panel-group-id", "test-group");
276
+ });
277
+ });
278
+
259
279
  describe("DEV warnings", () => {
260
280
  it("should warn about unstable layouts without id and order props", () => {
261
281
  act(() => {