@refinedev/devtools 1.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.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -0
  3. package/dist/components/devtools-pin.d.ts +10 -0
  4. package/dist/components/devtools-pin.d.ts.map +1 -0
  5. package/dist/components/devtools-selector.d.ts +8 -0
  6. package/dist/components/devtools-selector.d.ts.map +1 -0
  7. package/dist/components/icons/devtools-icon.d.ts +8 -0
  8. package/dist/components/icons/devtools-icon.d.ts.map +1 -0
  9. package/dist/components/icons/resize-handle-icon.d.ts +3 -0
  10. package/dist/components/icons/resize-handle-icon.d.ts.map +1 -0
  11. package/dist/components/icons/selector-button.d.ts +3 -0
  12. package/dist/components/icons/selector-button.d.ts.map +1 -0
  13. package/dist/components/resizable-pane.d.ts +19 -0
  14. package/dist/components/resizable-pane.d.ts.map +1 -0
  15. package/dist/components/selector-box.d.ts +8 -0
  16. package/dist/components/selector-box.d.ts.map +1 -0
  17. package/dist/components/selector-hint.d.ts +5 -0
  18. package/dist/components/selector-hint.d.ts.map +1 -0
  19. package/dist/esm/index.js +8 -0
  20. package/dist/esm/index.js.map +1 -0
  21. package/dist/iife/index.js +8 -0
  22. package/dist/iife/index.js.map +1 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +8 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/interfaces/placement.d.ts +2 -0
  28. package/dist/interfaces/placement.d.ts.map +1 -0
  29. package/dist/panel.d.ts +2 -0
  30. package/dist/panel.d.ts.map +1 -0
  31. package/dist/provider.d.ts +3 -0
  32. package/dist/provider.d.ts.map +1 -0
  33. package/dist/utilities/index.d.ts +37 -0
  34. package/dist/utilities/index.d.ts.map +1 -0
  35. package/dist/utilities/use-selector.d.ts +10 -0
  36. package/dist/utilities/use-selector.d.ts.map +1 -0
  37. package/package.json +62 -0
  38. package/src/components/devtools-pin.tsx +62 -0
  39. package/src/components/devtools-selector.tsx +127 -0
  40. package/src/components/icons/devtools-icon.tsx +91 -0
  41. package/src/components/icons/resize-handle-icon.tsx +27 -0
  42. package/src/components/icons/selector-button.tsx +81 -0
  43. package/src/components/resizable-pane.tsx +264 -0
  44. package/src/components/selector-box.tsx +80 -0
  45. package/src/components/selector-hint.tsx +63 -0
  46. package/src/define.d.ts +1 -0
  47. package/src/index.ts +2 -0
  48. package/src/interfaces/placement.ts +1 -0
  49. package/src/panel.tsx +93 -0
  50. package/src/provider.tsx +11 -0
  51. package/src/utilities/index.ts +142 -0
  52. package/src/utilities/use-selector.tsx +242 -0
@@ -0,0 +1,62 @@
1
+ import React from "react";
2
+ import { RefineDevtoolsIcon } from "./icons/devtools-icon";
3
+ import { getPinButtonTransform } from "src/utilities";
4
+ import { DevtoolsSelector } from "./devtools-selector";
5
+
6
+ type Props = {
7
+ onClick?: () => void;
8
+ active?: boolean;
9
+ groupHover?: boolean;
10
+ onSelectorHighlight: (name: string) => void;
11
+ onSelectorOpen: () => void;
12
+ };
13
+
14
+ export const DevtoolsPin = ({
15
+ active,
16
+ onClick,
17
+ groupHover,
18
+ onSelectorHighlight,
19
+ onSelectorOpen,
20
+ }: Props) => {
21
+ const [hover, setHover] = React.useState(false);
22
+
23
+ return (
24
+ <button
25
+ type="button"
26
+ style={{
27
+ position: "relative",
28
+ userSelect: "none",
29
+ WebkitUserSelect: "none",
30
+ background: "none",
31
+ border: "none",
32
+ padding: 0,
33
+ margin: 0,
34
+ display: "flex",
35
+ alignItems: "center",
36
+ justifyContent: "center",
37
+ fontWeight: "bold",
38
+ color: "white",
39
+ cursor: "pointer",
40
+ width: "100%",
41
+ height: "100%",
42
+ transition: "all ease-in-out 0.2s",
43
+ transform: `scale(${hover ? 1.05 : 1}) ${getPinButtonTransform(
44
+ groupHover,
45
+ )}`,
46
+ filter: `drop-shadow(0 0 ${
47
+ hover ? "8px" : "5px"
48
+ } rgba(71, 235, 235, ${hover ? "0.5" : "0.25"}))`,
49
+ }}
50
+ onMouseOver={() => setHover(true)}
51
+ onMouseOut={() => setHover(false)}
52
+ onClick={onClick}
53
+ >
54
+ <RefineDevtoolsIcon active={active} hovered={hover} />
55
+ <DevtoolsSelector
56
+ onSelectorOpen={onSelectorOpen}
57
+ onHighlight={onSelectorHighlight}
58
+ groupHover={hover}
59
+ />
60
+ </button>
61
+ );
62
+ };
@@ -0,0 +1,127 @@
1
+ import React from "react";
2
+ import { createPortal } from "react-dom";
3
+ import { useSelector } from "src/utilities/use-selector";
4
+ import { SelectorButtonIcon } from "./icons/selector-button";
5
+ import { SelectorBox } from "./selector-box";
6
+ import { SelectorHint } from "./selector-hint";
7
+
8
+ type Props = {
9
+ onSelectorOpen: () => void;
10
+ onHighlight: (name: string) => void;
11
+ groupHover?: boolean;
12
+ };
13
+
14
+ export const DevtoolsSelector = ({
15
+ onSelectorOpen,
16
+ onHighlight,
17
+ groupHover,
18
+ }: Props) => {
19
+ const [active, setActive] = React.useState(false);
20
+ const [hover, setHover] = React.useState(false);
21
+ const { rect, name } = useSelector(active);
22
+
23
+ const [selectorBoxRoot, setSelectorBoxRoot] =
24
+ React.useState<HTMLElement | null>(null);
25
+
26
+ React.useEffect(() => {
27
+ if (!selectorBoxRoot) {
28
+ const element = document.createElement("div");
29
+ element.id = "selector-box-root";
30
+
31
+ document.body.appendChild(element);
32
+
33
+ setSelectorBoxRoot(element);
34
+ }
35
+ }, []);
36
+
37
+ React.useEffect(() => {
38
+ if (active) {
39
+ document.body.style.cursor = "crosshair";
40
+ } else {
41
+ document.body.style.cursor = "default";
42
+ }
43
+ }, [active]);
44
+
45
+ React.useEffect(() => {
46
+ const onKeyDown = (e: KeyboardEvent) => {
47
+ if (!active) return;
48
+ if (!name) return;
49
+ if (e.code === "Space") {
50
+ e?.preventDefault();
51
+ e?.stopPropagation();
52
+ onHighlight(name);
53
+ setActive(false);
54
+ }
55
+ };
56
+
57
+ document.addEventListener("keydown", onKeyDown);
58
+
59
+ return () => {
60
+ document.removeEventListener("keydown", onKeyDown);
61
+ };
62
+ }, [name, onHighlight, active]);
63
+
64
+ React.useEffect(() => {
65
+ if (active) {
66
+ onSelectorOpen();
67
+ }
68
+ }, [active, onSelectorOpen]);
69
+
70
+ return (
71
+ <div
72
+ style={{
73
+ position: "absolute",
74
+ left: "calc((100px - ((100% - 42px) / 2)) + 7px)",
75
+ top: "calc((100% - 28px) / 2)",
76
+ transform: groupHover ? "translateX(0)" : "translateX(-40px)",
77
+ transitionDuration: "0.2s",
78
+ transitionProperty: "transform,opacity",
79
+ transitionTimingFunction: "ease-in-out",
80
+ pointerEvents: groupHover ? "auto" : "none",
81
+ height: 28,
82
+ width: 28,
83
+ }}
84
+ >
85
+ <div
86
+ role="button"
87
+ title="Element Selector"
88
+ onMouseOver={() => setHover(true)}
89
+ onMouseOut={() => setHover(false)}
90
+ onClick={(event) => {
91
+ event.preventDefault();
92
+ event.stopPropagation();
93
+ (document?.activeElement as HTMLElement)?.blur();
94
+ setActive((active) => !active);
95
+ }}
96
+ style={{
97
+ width: 28,
98
+ height: 28,
99
+ border: "none",
100
+ background: "none",
101
+ outline: "none",
102
+ margin: 0,
103
+ padding: 0,
104
+ cursor: "pointer",
105
+ transform: `scale(${hover ? 1.05 : 1})`,
106
+ transitionProperty: "transform,opacity",
107
+ transitionTimingFunction: "ease-in-out",
108
+ transitionDuration: "0.1s",
109
+ opacity: groupHover ? 1 : 0,
110
+ }}
111
+ >
112
+ <SelectorButtonIcon
113
+ width={28}
114
+ height={28}
115
+ style={{ pointerEvents: "none" }}
116
+ />
117
+ </div>
118
+ <SelectorHint active={active} groupHover={groupHover} />
119
+ {active &&
120
+ selectorBoxRoot &&
121
+ createPortal(
122
+ <SelectorBox {...rect} name={name} />,
123
+ selectorBoxRoot,
124
+ )}
125
+ </div>
126
+ );
127
+ };
@@ -0,0 +1,91 @@
1
+ import React from "react";
2
+
3
+ type Props = React.SVGProps<SVGSVGElement> & {
4
+ active?: boolean;
5
+ hovered?: boolean;
6
+ };
7
+
8
+ export const RefineDevtoolsIcon = ({ active, hovered, ...props }: Props) => (
9
+ <svg
10
+ width={42}
11
+ height={42}
12
+ viewBox="0 0 42 42"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ {...props}
16
+ >
17
+ <path
18
+ fillRule="evenodd"
19
+ clipRule="evenodd"
20
+ d="M16.3043 1.10851C19.2603 -0.369505 22.7397 -0.369505 25.6957 1.10851L36.1957 6.35852C39.753 8.13713 42 11.7729 42 15.75V26.25C42 30.2271 39.753 33.8629 36.1957 35.6415L25.6957 40.8915C22.7397 42.3695 19.2603 42.3695 16.3043 40.8915L5.80426 35.6415C2.24702 33.8629 0 30.2271 0 26.25V15.75C0 11.7729 2.24702 8.13713 5.80426 6.35852L16.3043 1.10851Z"
21
+ fill="#1D1E30"
22
+ />
23
+ <path
24
+ fillRule="evenodd"
25
+ clipRule="evenodd"
26
+ d="M14.7975 13.2C14.7975 9.77583 17.5733 7 20.9975 7C24.4217 7 27.1975 9.77583 27.1975 13.2V28.8C27.1975 32.2242 24.4217 35 20.9975 35C17.5733 35 14.7975 32.2242 14.7975 28.8V13.2ZM20.9975 8C18.1256 8 15.7975 10.3281 15.7975 13.2V28.8C15.7975 31.6719 18.1256 34 20.9975 34C23.8694 34 26.1975 31.6719 26.1975 28.8V13.2C26.1975 10.3281 23.8694 8 20.9975 8Z"
27
+ fill="url(#devtools_icon_gradient_1)"
28
+ />
29
+ <path
30
+ fillRule="evenodd"
31
+ clipRule="evenodd"
32
+ d="M16.5279 2.05573C19.3431 0.648091 22.6569 0.648091 25.4721 2.05573L35.4721 7.05573C38.86 8.74965 41 12.2123 41 16V26C41 29.7877 38.86 33.2504 35.4721 34.9443L25.4721 39.9443C22.6569 41.3519 19.3431 41.3519 16.5279 39.9443L6.52786 34.9443C3.14002 33.2504 1 29.7877 1 26V16C1 12.2123 3.14002 8.74965 6.52786 7.05573L16.5279 2.05573ZM16.9751 2.95016C19.5088 1.68328 22.4912 1.68328 25.0249 2.95016L35.0249 7.95016C38.074 9.47468 40 12.5911 40 16V26C40 29.4089 38.074 32.5253 35.0249 34.0498L25.0249 39.0498C22.4912 40.3167 19.5088 40.3167 16.9751 39.0498L6.97508 34.0498C3.92602 32.5253 2 29.4089 2 26V16C2 12.5911 3.92602 9.47468 6.97508 7.95016L16.9751 2.95016Z"
33
+ fill="url(#devtools_icon_gradient_2)"
34
+ />
35
+ <path
36
+ fillRule="evenodd"
37
+ clipRule="evenodd"
38
+ d="M16.9751 2.95016C19.5088 1.68328 22.4912 1.68328 25.0249 2.95016L35.0249 7.95016C38.074 9.47468 40 12.5911 40 16V26C40 29.4089 38.074 32.5253 35.0249 34.0498L25.0249 39.0498C22.4912 40.3167 19.5088 40.3167 16.9751 39.0498L6.97508 34.0498C3.92602 32.5253 2 29.4089 2 26V16C2 12.5911 3.92602 9.47468 6.97508 7.95016L16.9751 2.95016ZM20.9975 7C17.5733 7 14.7975 9.77583 14.7975 13.2V28.8C14.7975 32.2242 17.5733 35 20.9975 35C24.4217 35 27.1975 32.2242 27.1975 28.8V13.2C27.1975 9.77583 24.4217 7 20.9975 7Z"
39
+ fill="url(#devtools_icon_gradient_3)"
40
+ />
41
+ <circle
42
+ cx={21}
43
+ cy={13.3301}
44
+ r={4}
45
+ fill="url(#devtools_icon_gradient_2)"
46
+ style={{
47
+ transition: "transform ease-in-out 0.2s",
48
+ transform: `translateY(${
49
+ active ? "0" : hovered ? "15px" : "15px"
50
+ })`,
51
+ }}
52
+ />
53
+ <defs>
54
+ <linearGradient
55
+ id="devtools_icon_gradient_1"
56
+ x1={21}
57
+ y1={7}
58
+ x2={21}
59
+ y2={35}
60
+ gradientUnits="userSpaceOnUse"
61
+ >
62
+ <stop stopColor="#47EBEB" />
63
+ <stop offset={1} stopColor="#47EBEB" stopOpacity={0.5} />
64
+ </linearGradient>
65
+ <linearGradient
66
+ id="devtools_icon_gradient_2"
67
+ x1={21}
68
+ y1={1}
69
+ x2={21}
70
+ y2={41}
71
+ gradientUnits="userSpaceOnUse"
72
+ >
73
+ <stop stopColor="#47EBEB" />
74
+ <stop offset={0.5} stopColor="#47EBEB" stopOpacity={0.5} />
75
+ <stop offset={1} stopColor="#47EBEB" stopOpacity={0.5} />
76
+ </linearGradient>
77
+ <radialGradient
78
+ id="devtools_icon_gradient_3"
79
+ cx={0}
80
+ cy={0}
81
+ r={1}
82
+ gradientUnits="userSpaceOnUse"
83
+ gradientTransform="translate(21 1) rotate(90) scale(40)"
84
+ >
85
+ <stop stopColor="#47EBEB" stopOpacity={0} />
86
+ <stop offset={0.5} stopColor="#47EBEB" stopOpacity={0.25} />
87
+ <stop offset={1} stopColor="#47EBEB" stopOpacity={0.5} />
88
+ </radialGradient>
89
+ </defs>
90
+ </svg>
91
+ );
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+
3
+ export const ResizeHandleIcon = (props: React.SVGProps<SVGSVGElement>) => (
4
+ <svg
5
+ width={10}
6
+ height={26}
7
+ viewBox="0 0 10 26"
8
+ fill="none"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ {...props}
11
+ >
12
+ <rect x={0.5} y={0.5} width={9} height={25} rx={4.5} fill="#1D1E30" />
13
+ <path
14
+ d="M7 5C7 6.10457 6.10457 7 5 7C3.89543 7 3 6.10457 3 5C3 3.89543 3.89543 3 5 3C6.10457 3 7 3.89543 7 5Z"
15
+ fill="#303450"
16
+ />
17
+ <path
18
+ d="M7 13C7 14.1046 6.10457 15 5 15C3.89543 15 3 14.1046 3 13C3 11.8954 3.89543 11 5 11C6.10457 11 7 11.8954 7 13Z"
19
+ fill="#303450"
20
+ />
21
+ <path
22
+ d="M7 21C7 22.1046 6.10457 23 5 23C3.89543 23 3 22.1046 3 21C3 19.8954 3.89543 19 5 19C6.10457 19 7 19.8954 7 21Z"
23
+ fill="#303450"
24
+ />
25
+ <rect x={0.5} y={0.5} width={9} height={25} rx={4.5} stroke="#303450" />
26
+ </svg>
27
+ );
@@ -0,0 +1,81 @@
1
+ import React from "react";
2
+
3
+ export const SelectorButtonIcon = (props: React.SVGProps<SVGSVGElement>) => (
4
+ <svg
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ width={42}
7
+ height={42}
8
+ viewBox="0 0 42 42"
9
+ fill="none"
10
+ {...props}
11
+ >
12
+ <g clipPath="url(#selector-button-a)">
13
+ <path
14
+ fill="#1D1E30"
15
+ fillRule="evenodd"
16
+ d="M16.304 1.109a10.5 10.5 0 0 1 9.392 0l10.5 5.25A10.5 10.5 0 0 1 42 15.75v10.5a10.5 10.5 0 0 1-5.804 9.392l-10.5 5.25a10.5 10.5 0 0 1-9.392 0l-10.5-5.25A10.5 10.5 0 0 1 0 26.25v-10.5a10.5 10.5 0 0 1 5.804-9.391l10.5-5.25Z"
17
+ clipRule="evenodd"
18
+ />
19
+ <path
20
+ fill="url(#selector-button-b)"
21
+ fillRule="evenodd"
22
+ d="M16.528 2.056a10 10 0 0 1 8.944 0l10 5A10 10 0 0 1 41 16v10a10 10 0 0 1-5.528 8.944l-10 5a10 10 0 0 1-8.944 0l-10-5A10 10 0 0 1 1 26V16a10 10 0 0 1 5.528-8.944l10-5Zm.447.894a9 9 0 0 1 8.05 0l10 5A9 9 0 0 1 40 16v10a9 9 0 0 1-4.975 8.05l-10 5a9 9 0 0 1-8.05 0l-10-5A9 9 0 0 1 2 26V16a9 9 0 0 1 4.975-8.05l10-5Z"
23
+ clipRule="evenodd"
24
+ />
25
+ <path
26
+ fill="url(#selector-button-c)"
27
+ fillRule="evenodd"
28
+ d="M16.975 2.95a9 9 0 0 1 8.05 0l10 5A9 9 0 0 1 40 16v10a9 9 0 0 1-4.975 8.05l-10 5a9 9 0 0 1-8.05 0l-10-5A9 9 0 0 1 2 26V16a9 9 0 0 1 4.975-8.05l10-5Z"
29
+ clipRule="evenodd"
30
+ />
31
+ <path
32
+ stroke="url(#selector-button-d)"
33
+ strokeLinecap="round"
34
+ strokeLinejoin="round"
35
+ strokeWidth={1.5}
36
+ d="M32 21c0 6.075-4.925 11-11 11m11-11c0-6.075-4.925-11-11-11m11 11h-4.4M21 32c-6.075 0-11-4.925-11-11m11 11v-4.4M10 21c0-6.075 4.925-11 11-11M10 21h4.4M21 10v4.4"
37
+ />
38
+ </g>
39
+ <defs>
40
+ <radialGradient
41
+ id="selector-button-c"
42
+ cx={0}
43
+ cy={0}
44
+ r={1}
45
+ gradientTransform="matrix(0 40 -40 0 21 1)"
46
+ gradientUnits="userSpaceOnUse"
47
+ >
48
+ <stop stopColor="#47EBEB" stopOpacity={0} />
49
+ <stop offset={0.5} stopColor="#47EBEB" stopOpacity={0.25} />
50
+ <stop offset={1} stopColor="#47EBEB" stopOpacity={0.5} />
51
+ </radialGradient>
52
+ <linearGradient
53
+ id="selector-button-b"
54
+ x1={21}
55
+ x2={21}
56
+ y1={1}
57
+ y2={41}
58
+ gradientUnits="userSpaceOnUse"
59
+ >
60
+ <stop stopColor="#47EBEB" />
61
+ <stop offset={0.5} stopColor="#47EBEB" stopOpacity={0.5} />
62
+ <stop offset={1} stopColor="#47EBEB" stopOpacity={0.5} />
63
+ </linearGradient>
64
+ <linearGradient
65
+ id="selector-button-d"
66
+ x1={21}
67
+ y1={1}
68
+ x2={21}
69
+ y2={41}
70
+ gradientUnits="userSpaceOnUse"
71
+ >
72
+ <stop stopColor="#47EBEB" />
73
+ <stop offset={0.5} stopColor="#47EBEB" stopOpacity={0.75} />
74
+ <stop offset={1} stopColor="#47EBEB" stopOpacity={0.5} />
75
+ </linearGradient>
76
+ <clipPath id="selector-button-a">
77
+ <path fill="#fff" d="M0 0h42v42H0z" />
78
+ </clipPath>
79
+ </defs>
80
+ </svg>
81
+ );
@@ -0,0 +1,264 @@
1
+ import React from "react";
2
+ import { Placement } from "src/interfaces/placement";
3
+ import {
4
+ MIN_PANEL_HEIGHT,
5
+ MIN_PANEL_WIDTH,
6
+ getDefaultPanelSize,
7
+ getMaxPanelHeight,
8
+ getMaxPanelWidth,
9
+ getPanelPosition,
10
+ getPanelToggleTransforms,
11
+ } from "src/utilities";
12
+ import { ResizeHandleIcon } from "./icons/resize-handle-icon";
13
+
14
+ type Props = {
15
+ placement: Placement;
16
+ defaultWidth?: number;
17
+ minWidth?: number;
18
+ maxWidth?: number;
19
+ defaultHeight?: number;
20
+ minHeight?: number;
21
+ maxHeight?: number;
22
+ children: ({ resizing }: { resizing: string | null }) => React.ReactNode;
23
+ onResize?: (width: number, height: number) => void;
24
+ visible?: boolean;
25
+ };
26
+
27
+ export const ResizablePane = ({ placement, visible, children }: Props) => {
28
+ const [hover, setHover] = React.useState(false);
29
+ const [resizing, setResizing] = React.useState<
30
+ "lx" | "rx" | "ty" | "by" | null
31
+ >(null);
32
+ const [resizePosition, setResizePosition] = React.useState<{
33
+ x: number;
34
+ y: number;
35
+ } | null>(null);
36
+ const [panelSize, setPanelSize] = React.useState<
37
+ Record<"width" | "height", number>
38
+ >(getDefaultPanelSize(placement));
39
+
40
+ React.useEffect(() => {
41
+ const handleResize = () => {
42
+ setPanelSize((p) => getDefaultPanelSize(placement, p));
43
+ };
44
+
45
+ handleResize();
46
+
47
+ window.addEventListener("resize", handleResize);
48
+
49
+ return () => {
50
+ window.removeEventListener("resize", handleResize);
51
+ };
52
+ }, [placement]);
53
+
54
+ React.useEffect(() => {
55
+ const handleMouseUp = () => {
56
+ setResizing(null);
57
+ };
58
+
59
+ if (resizing !== null) {
60
+ window.addEventListener("mouseup", handleMouseUp);
61
+
62
+ return () => {
63
+ window.removeEventListener("mouseup", handleMouseUp);
64
+ };
65
+ }
66
+
67
+ return;
68
+ }, [resizing]);
69
+
70
+ React.useEffect(() => {
71
+ const currentCursor = document.body.style.cursor;
72
+
73
+ if (resizing?.includes("x")) {
74
+ document.body.style.cursor = "col-resize";
75
+ } else if (resizing?.includes("y")) {
76
+ document.body.style.cursor = "row-resize";
77
+ }
78
+
79
+ return () => {
80
+ document.body.style.cursor = currentCursor;
81
+ };
82
+ }, [resizing]);
83
+
84
+ React.useEffect(() => {
85
+ const handleMouseMove = (e: MouseEvent) => {
86
+ if (resizing?.[1] === "x") {
87
+ const diff = e.clientX - (resizePosition?.x ?? e.clientX);
88
+ const newWidth =
89
+ panelSize.width + (resizing === "lx" ? -diff : diff) * 2;
90
+
91
+ setPanelSize((p) => ({
92
+ ...p,
93
+ width: Math.min(
94
+ getMaxPanelWidth(placement),
95
+ Math.max(MIN_PANEL_WIDTH, newWidth),
96
+ ),
97
+ }));
98
+ } else if (resizing?.[1] === "y") {
99
+ const diff = e.clientY - (resizePosition?.y ?? e.clientY);
100
+ const newHeight =
101
+ panelSize.height + (resizing === "ty" ? -diff : diff) * 1;
102
+
103
+ setPanelSize((p) => ({
104
+ ...p,
105
+ height: Math.min(
106
+ getMaxPanelHeight(placement),
107
+ Math.max(MIN_PANEL_HEIGHT, newHeight),
108
+ ),
109
+ }));
110
+ }
111
+ };
112
+
113
+ if (resizing !== null) {
114
+ window.addEventListener("mousemove", handleMouseMove);
115
+
116
+ return () => {
117
+ window.removeEventListener("mousemove", handleMouseMove);
118
+ };
119
+ }
120
+
121
+ return;
122
+ }, [resizing, placement]);
123
+
124
+ return (
125
+ <div
126
+ style={{
127
+ position: "absolute",
128
+ borderRadius: "8px",
129
+ boxShadow: "0 0 10px rgba(0, 0, 0, 0.5)",
130
+ border: "1px solid rgba(0, 0, 0, 0.5)",
131
+ transitionProperty: "transform, opacity",
132
+ transitionTimingFunction: "ease-in-out",
133
+ transitionDuration: "0.2s",
134
+ ...getPanelPosition(placement),
135
+ opacity: visible ? 1 : 0,
136
+ transform: `${
137
+ getPanelPosition(placement).transform
138
+ } ${getPanelToggleTransforms(visible ?? false)}`,
139
+ ...panelSize,
140
+ }}
141
+ onMouseEnter={() => {
142
+ setHover(true);
143
+ }}
144
+ onMouseLeave={() => {
145
+ setHover(false);
146
+ }}
147
+ >
148
+ {children({ resizing })}
149
+ {/* */}
150
+ <React.Fragment>
151
+ <div
152
+ style={{
153
+ position: "absolute",
154
+ left: 0,
155
+ top: "50%",
156
+ width: "10px",
157
+ height: "26px",
158
+ transform: "translateY(-13px) translateX(-5px)",
159
+ cursor: "col-resize",
160
+ transition: "opacity ease-in-out 0.2s",
161
+ pointerEvents: hover || resizing ? "auto" : "none",
162
+ opacity: hover || resizing ? 1 : 0,
163
+ }}
164
+ onMouseDown={(event) => {
165
+ setResizing("lx");
166
+ setResizePosition({
167
+ x: event.clientX,
168
+ y: event.clientY,
169
+ });
170
+
171
+ event.preventDefault();
172
+ }}
173
+ >
174
+ <ResizeHandleIcon />
175
+ </div>
176
+ <div
177
+ style={{
178
+ position: "absolute",
179
+ right: 0,
180
+ top: "50%",
181
+ width: "10px",
182
+ height: "26px",
183
+ transform: `translateY(-13px) translateX(5px)`,
184
+ cursor: "col-resize",
185
+ transition: "opacity ease-in-out 0.2s",
186
+ pointerEvents: hover || resizing ? "auto" : "none",
187
+ opacity: hover || resizing ? 1 : 0,
188
+ }}
189
+ onMouseDown={(event) => {
190
+ setResizing("rx");
191
+ setResizePosition({
192
+ x: event.clientX,
193
+ y: event.clientY,
194
+ });
195
+
196
+ event.preventDefault();
197
+ }}
198
+ >
199
+ <ResizeHandleIcon />
200
+ </div>
201
+ <div
202
+ style={{
203
+ position: "absolute",
204
+ left: "50%",
205
+ top: 0,
206
+ width: "26px",
207
+ height: "10px",
208
+ transform: "translateY(-5px) translateX(-13px)",
209
+ cursor: "row-resize",
210
+ transition: "opacity ease-in-out 0.2s",
211
+ pointerEvents: hover || resizing ? "auto" : "none",
212
+ opacity: hover || resizing ? 1 : 0,
213
+ }}
214
+ onMouseDown={(event) => {
215
+ setResizing("ty");
216
+ setResizePosition({
217
+ x: event.clientX,
218
+ y: event.clientY,
219
+ });
220
+
221
+ event.preventDefault();
222
+ }}
223
+ >
224
+ <ResizeHandleIcon
225
+ style={{
226
+ transform: "rotate(90deg)",
227
+ transformOrigin: "13px 13px",
228
+ }}
229
+ />
230
+ </div>
231
+ <div
232
+ style={{
233
+ position: "absolute",
234
+ left: "50%",
235
+ bottom: 0,
236
+ width: "26px",
237
+ height: "10px",
238
+ transform: "translateY(5px) translateX(-13px)",
239
+ cursor: "row-resize",
240
+ transition: "opacity ease-in-out 0.2s",
241
+ pointerEvents: hover || resizing ? "auto" : "none",
242
+ opacity: hover || resizing ? 1 : 0,
243
+ }}
244
+ onMouseDown={(event) => {
245
+ setResizing("by");
246
+ setResizePosition({
247
+ x: event.clientX,
248
+ y: event.clientY,
249
+ });
250
+
251
+ event.preventDefault();
252
+ }}
253
+ >
254
+ <ResizeHandleIcon
255
+ style={{
256
+ transform: "rotate(90deg)",
257
+ transformOrigin: "13px 13px",
258
+ }}
259
+ />
260
+ </div>
261
+ </React.Fragment>
262
+ </div>
263
+ );
264
+ };