react-resizable-panels 0.0.6 → 0.0.8

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.
@@ -1,34 +1,44 @@
1
1
  import { ReactNode, useContext, useEffect, useState } from "react";
2
2
 
3
3
  import useUniqueId from "./hooks/useUniqueId";
4
- import { PanelGroupContext } from "./PanelContexts";
5
- import { ResizeHandler } from "./types";
4
+ import { PanelContext, PanelGroupContext } from "./PanelContexts";
5
+ import type { ResizeHandler, ResizeEvent } from "./types";
6
6
 
7
7
  export default function PanelResizeHandle({
8
8
  children = null,
9
9
  className = "",
10
10
  disabled = false,
11
+ id: idProp = null,
11
12
  }: {
12
13
  children?: ReactNode;
13
14
  className?: string;
14
15
  disabled?: boolean;
16
+ id?: string | null;
15
17
  }) {
16
- const context = useContext(PanelGroupContext);
17
- if (context === null) {
18
+ const panelContext = useContext(PanelContext);
19
+ const panelGroupContext = useContext(PanelGroupContext);
20
+ if (panelContext === null || panelGroupContext === null) {
18
21
  throw Error(
19
22
  `PanelResizeHandle components must be rendered within a PanelGroup container`
20
23
  );
21
24
  }
22
25
 
23
- const id = useUniqueId();
26
+ const id = useUniqueId(idProp);
24
27
 
25
- const { direction, groupId, registerResizeHandle } = context;
28
+ const { activeHandleId } = panelContext;
29
+ const {
30
+ direction,
31
+ groupId,
32
+ registerResizeHandle,
33
+ startDragging,
34
+ stopDragging,
35
+ } = panelGroupContext;
36
+
37
+ const isDragging = activeHandleId === id;
26
38
 
27
- const setGroupId = useState<string | null>(null);
28
39
  const [resizeHandler, setResizeHandler] = useState<ResizeHandler | null>(
29
40
  null
30
41
  );
31
- const [isDragging, setIsDragging] = useState(false);
32
42
 
33
43
  useEffect(() => {
34
44
  if (disabled) {
@@ -47,40 +57,38 @@ export default function PanelResizeHandle({
47
57
  document.body.style.cursor =
48
58
  direction === "horizontal" ? "ew-resize" : "ns-resize";
49
59
 
50
- const onMouseLeave = (_: MouseEvent) => {
51
- setIsDragging(false);
52
- };
53
-
54
- const onMouseMove = (event: MouseEvent) => {
60
+ const onMove = (event: ResizeEvent) => {
55
61
  resizeHandler(event);
56
62
  };
57
63
 
58
- const onMouseUp = (_: MouseEvent) => {
59
- setIsDragging(false);
60
- };
61
-
62
- document.body.addEventListener("mouseleave", onMouseLeave);
63
- document.body.addEventListener("mousemove", onMouseMove);
64
- document.body.addEventListener("mouseup", onMouseUp);
64
+ document.body.addEventListener("mouseleave", stopDragging);
65
+ document.body.addEventListener("mousemove", onMove);
66
+ document.body.addEventListener("touchmove", onMove);
67
+ document.body.addEventListener("mouseup", stopDragging);
65
68
 
66
69
  return () => {
67
70
  document.body.style.cursor = "";
68
71
 
69
- document.body.removeEventListener("mouseleave", onMouseLeave);
70
- document.body.removeEventListener("mousemove", onMouseMove);
71
- document.body.removeEventListener("mouseup", onMouseUp);
72
+ document.body.removeEventListener("mouseleave", stopDragging);
73
+ document.body.removeEventListener("mousemove", onMove);
74
+ document.body.removeEventListener("touchmove", onMove);
75
+ document.body.removeEventListener("mouseup", stopDragging);
72
76
  };
73
- }, [direction, disabled, isDragging, resizeHandler]);
77
+ }, [direction, disabled, isDragging, resizeHandler, stopDragging]);
74
78
 
75
79
  return (
76
80
  <div
77
81
  className={className}
78
82
  data-panel-group-id={groupId}
79
83
  data-panel-resize-handle-id={id}
80
- onMouseDown={() => setIsDragging(true)}
81
- onMouseUp={() => setIsDragging(false)}
84
+ onMouseDown={() => startDragging(id)}
85
+ onMouseUp={stopDragging}
86
+ onTouchCancel={stopDragging}
87
+ onTouchEnd={stopDragging}
88
+ onTouchStart={() => startDragging(id)}
82
89
  style={{
83
90
  cursor: direction === "horizontal" ? "ew-resize" : "ns-resize",
91
+ touchAction: "none",
84
92
  }}
85
93
  >
86
94
  {children}
@@ -2,11 +2,11 @@ import { useRef } from "react";
2
2
 
3
3
  let counter = 0;
4
4
 
5
- export default function useUniqueId(): string {
6
- const idRef = useRef<number | null>(null);
5
+ export default function useUniqueId(id: string | null = null): string {
6
+ const idRef = useRef<string | null>(id);
7
7
  if (idRef.current === null) {
8
- idRef.current = counter++;
8
+ idRef.current = "" + counter++;
9
9
  }
10
10
 
11
- return "" + idRef.current;
11
+ return idRef.current;
12
12
  }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import Panel from "./Panel";
2
+ import { PanelContext } from "./PanelContexts";
2
3
  import PanelGroup from "./PanelGroup";
3
4
  import PanelResizeHandle from "./PanelResizeHandle";
4
5
 
5
- export { Panel, PanelGroup, PanelResizeHandle };
6
+ export { Panel, PanelContext, PanelGroup, PanelResizeHandle };
package/src/types.ts CHANGED
@@ -7,4 +7,5 @@ export type PanelData = {
7
7
  order: number | null;
8
8
  };
9
9
 
10
- export type ResizeHandler = (event: MouseEvent) => void;
10
+ export type ResizeEvent = MouseEvent | TouchEvent;
11
+ export type ResizeHandler = (event: ResizeEvent) => void;
@@ -0,0 +1,49 @@
1
+ import { PanelData } from "../types";
2
+
3
+ type SerializedPanelGroupState = { [panelIds: string]: number[] };
4
+
5
+ function loadSerializedPanelGroupState(
6
+ autoSaveId: string
7
+ ): SerializedPanelGroupState | null {
8
+ try {
9
+ const serialized = localStorage.getItem(`PanelGroup:sizes:${autoSaveId}`);
10
+ if (serialized) {
11
+ const parsed = JSON.parse(serialized);
12
+ if (typeof parsed === "object" && parsed != null) {
13
+ return parsed;
14
+ }
15
+ }
16
+ } catch (error) {}
17
+
18
+ return null;
19
+ }
20
+
21
+ export function loadPanelLayout(
22
+ autoSaveId: string,
23
+ panelIds: string[]
24
+ ): number[] | null {
25
+ const state = loadSerializedPanelGroupState(autoSaveId);
26
+ if (state) {
27
+ return state[panelIds.join(",")] ?? null;
28
+ }
29
+
30
+ return null;
31
+ }
32
+
33
+ export function savePanelGroupLayout(
34
+ autoSaveId: string,
35
+ panelIds: string[],
36
+ sizes: number[]
37
+ ): void {
38
+ const state = loadSerializedPanelGroupState(autoSaveId) || {};
39
+ state[panelIds.join(",")] = sizes;
40
+
41
+ try {
42
+ localStorage.setItem(
43
+ `PanelGroup:sizes:${autoSaveId}`,
44
+ JSON.stringify(state)
45
+ );
46
+ } catch (error) {
47
+ console.error(error);
48
+ }
49
+ }
@@ -0,0 +1,44 @@
1
+ import { ResizeEvent } from "../types";
2
+
3
+ export type Coordinates = {
4
+ screenX: number;
5
+ screenY: number;
6
+ };
7
+
8
+ export type Movement = {
9
+ movementX: number;
10
+ movementY: number;
11
+ };
12
+
13
+ // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
14
+ export function getUpdatedCoordinates(
15
+ event: ResizeEvent,
16
+ prevCoordinates: Coordinates
17
+ ): Coordinates & Movement {
18
+ const { screenX: prevScreenX, screenY: prevScreenY } = prevCoordinates;
19
+
20
+ const getMovementBetween = (current: number, prev: number) =>
21
+ prev === 0 ? 0 : current - prev;
22
+
23
+ if (isTouchMoveEvent(event)) {
24
+ const firstTouch = event.touches[0];
25
+
26
+ return {
27
+ movementX: getMovementBetween(firstTouch.screenX, prevScreenX),
28
+ movementY: getMovementBetween(firstTouch.screenY, prevScreenY),
29
+ screenX: firstTouch.screenX,
30
+ screenY: firstTouch.screenY,
31
+ };
32
+ }
33
+
34
+ return {
35
+ movementX: getMovementBetween(event.screenX, prevScreenX),
36
+ movementY: getMovementBetween(event.screenY, prevScreenY),
37
+ screenX: event.screenX,
38
+ screenY: event.screenY,
39
+ };
40
+ }
41
+
42
+ export function isTouchMoveEvent(event: ResizeEvent): event is TouchEvent {
43
+ return event.type === "touchmove";
44
+ }