@rnaga/wp-next-ui 1.0.5 → 1.0.6

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/DraggableBox.d.ts CHANGED
@@ -34,6 +34,7 @@ export declare const DraggableBox: (props: {
34
34
  slotSxProps?: SlotSxProps;
35
35
  zIndexLayer?: number;
36
36
  placement?: "target" | "left";
37
+ resizable?: boolean;
37
38
  }) => import("react/jsx-runtime").JSX.Element;
38
39
  export {};
39
40
  //# sourceMappingURL=DraggableBox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DraggableBox.d.ts","sourceRoot":"","sources":["../src/DraggableBox.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,EACZ,SAAS,EAKV,MAAM,OAAO,CAAC;AACf,OAAO,EAAgB,OAAO,EAAE,MAAM,eAAe,CAAC;AAMtD,KAAK,WAAW,GAAG;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1C,GAAG,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACpC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC/B,4CAqNA,CAAC"}
1
+ {"version":3,"file":"DraggableBox.d.ts","sourceRoot":"","sources":["../src/DraggableBox.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,EACZ,SAAS,EAKV,MAAM,OAAO,CAAC;AACf,OAAO,EAAmB,OAAO,EAAE,MAAM,eAAe,CAAC;AAOzD,KAAK,WAAW,GAAG;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC1C,GAAG,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACpC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,4CAkbA,CAAC"}
package/DraggableBox.js CHANGED
@@ -14,13 +14,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
14
14
  * - slotSxProps: Style overrides for the header and title.
15
15
  */
16
16
  import { useCallback, useEffect, useRef, useState, } from "react";
17
- import { Box } from "@mui/material";
17
+ import { Box, IconButton } from "@mui/material";
18
+ import CloseIcon from "@mui/icons-material/Close";
18
19
  import { Typography } from "./Typography";
19
20
  import { Background } from "./Background";
20
21
  import { Portal } from "./portal";
21
22
  export const DraggableBox = (props) => {
22
23
  // Destructure props
23
- const { children, targetRef, ref: selfRef, title, size, onClose, open, sx, slotSxProps, offset: initialOffset = {}, zIndexLayer = 0, placement = "left", } = props;
24
+ const { children, targetRef, ref: selfRef, title, size, onClose, open, sx, slotSxProps, offset: initialOffset = {}, zIndexLayer = 0, placement = "left", resizable = false, } = props;
24
25
  // Provide default offset values for the box
25
26
  const { left = 0, top = 0 } = initialOffset;
26
27
  // Reference to the draggable box DOM element
@@ -31,6 +32,12 @@ export const DraggableBox = (props) => {
31
32
  const [isDragging, setIsDragging] = useState(false);
32
33
  // Stores the mouse down offset within the box
33
34
  const [offset, setOffset] = useState({ x: 0, y: 0 });
35
+ // State to store the current size of the draggable box
36
+ const [boxSize, setBoxSize] = useState({ width: 0, height: 0 });
37
+ // Determines if the box is currently being resized and from which direction
38
+ const [isResizing, setIsResizing] = useState(null);
39
+ // Stores the initial mouse position when resizing starts
40
+ const [resizeStart, setResizeStart] = useState({ x: 0, y: 0, width: 0, height: 0 });
34
41
  /**
35
42
  * Ensures the new position is within the browser window bounds.
36
43
  * Returns null if the position would place the box partially off-screen.
@@ -46,35 +53,51 @@ export const DraggableBox = (props) => {
46
53
  };
47
54
  /**
48
55
  * Callback ref to get the DOM element for the draggable box.
49
- * Requires a targetRef to position the box relative to another element.
56
+ * Positions the box relative to a target element if provided, or centers it on screen.
50
57
  */
51
58
  const callbackRef = useCallback((ref) => {
52
- if (!ref || !targetRef?.current)
59
+ if (!ref)
53
60
  return;
54
61
  boxRef.current = ref;
55
62
  if (selfRef) {
56
63
  // If a selfRef is provided, assign the boxRef to it
57
64
  selfRef.current = ref;
58
65
  }
59
- // Calculate the referenced element’s position
60
- const rect = targetRef.current.getBoundingClientRect();
61
66
  const boxWidth = boxRef.current.offsetWidth || 0;
62
67
  const boxHeight = boxRef.current.offsetHeight || 0;
63
- // Compute initial position based on target element
64
- let newX = rect.left + left - boxWidth;
65
- let newY = rect.bottom - boxHeight / 2 + top;
66
- // if placemenet is "target", x and y are relative to the target element
67
- if (placement === "target") {
68
- newX = rect.left;
69
- newY = rect.top;
68
+ let newX;
69
+ let newY;
70
+ if (targetRef?.current) {
71
+ // Calculate the referenced element's position
72
+ const rect = targetRef.current.getBoundingClientRect();
73
+ // Compute initial position based on target element
74
+ newX = rect.left + left - boxWidth;
75
+ newY = rect.bottom - boxHeight / 2 + top;
76
+ // if placement is "target", x and y are relative to the target element
77
+ if (placement === "target") {
78
+ newX = rect.left;
79
+ newY = rect.top;
80
+ }
81
+ }
82
+ else {
83
+ // Center the box on screen if no targetRef is provided
84
+ newX = (window.innerWidth - boxWidth) / 2 + left;
85
+ newY = (window.innerHeight - boxHeight) / 2 + top;
70
86
  }
71
87
  // If the box goes off-screen at the bottom, adjust upward
72
88
  if (newY + boxHeight > window.innerHeight) {
73
89
  newY = window.innerHeight - boxHeight;
74
90
  }
91
+ // If the box goes off-screen at the right, adjust leftward
92
+ if (newX + boxWidth > window.innerWidth) {
93
+ newX = window.innerWidth - boxWidth;
94
+ }
95
+ // Ensure minimum position is not negative
96
+ newX = Math.max(0, newX);
97
+ newY = Math.max(0, newY);
75
98
  // Store the position state
76
99
  setPosition({ x: newX, y: newY });
77
- }, [targetRef, left, top]);
100
+ }, [targetRef, left, top, placement, selfRef]);
78
101
  /**
79
102
  * Called when the user presses the mouse button within the box header.
80
103
  * Captures the offset from the mouse position to the box's top-left corner.
@@ -91,21 +114,79 @@ export const DraggableBox = (props) => {
91
114
  * Updates the box position while respecting window bounds.
92
115
  */
93
116
  const handleMouseMove = (e) => {
94
- if (!isDragging || !boxRef.current)
95
- return;
96
- const { offsetWidth, offsetHeight } = boxRef.current;
97
- const newPos = clampPosition(e.clientX - offset.x, e.clientY - offset.y, offsetWidth, offsetHeight);
98
- if (newPos)
99
- setPosition(newPos);
117
+ if (isDragging && boxRef.current) {
118
+ const { offsetWidth, offsetHeight } = boxRef.current;
119
+ const newPos = clampPosition(e.clientX - offset.x, e.clientY - offset.y, offsetWidth, offsetHeight);
120
+ if (newPos)
121
+ setPosition(newPos);
122
+ }
123
+ if (isResizing && boxRef.current) {
124
+ const deltaX = e.clientX - resizeStart.x;
125
+ const deltaY = e.clientY - resizeStart.y;
126
+ let newWidth = resizeStart.width;
127
+ let newHeight = resizeStart.height;
128
+ if (isResizing.includes("right")) {
129
+ newWidth = Math.max(300, resizeStart.width + deltaX);
130
+ }
131
+ if (isResizing.includes("left")) {
132
+ newWidth = Math.max(300, resizeStart.width - deltaX);
133
+ }
134
+ if (isResizing.includes("bottom")) {
135
+ newHeight = Math.max(200, resizeStart.height + deltaY);
136
+ }
137
+ if (isResizing.includes("top")) {
138
+ newHeight = Math.max(200, resizeStart.height - deltaY);
139
+ }
140
+ setBoxSize({ width: newWidth, height: newHeight });
141
+ }
100
142
  };
101
143
  // Called when the mouse is released. Ends the dragging session.
102
- const handleMouseUp = () => setIsDragging(false);
144
+ const handleMouseUp = () => {
145
+ setIsDragging(false);
146
+ setIsResizing(null);
147
+ };
148
+ /**
149
+ * Called when the user presses the mouse button on a resize handle.
150
+ * Captures the initial state for resizing.
151
+ */
152
+ const handleResizeMouseDown = useCallback((e, direction) => {
153
+ e.stopPropagation();
154
+ setIsResizing(direction);
155
+ const rect = boxRef.current?.getBoundingClientRect();
156
+ if (rect) {
157
+ setResizeStart({
158
+ x: e.clientX,
159
+ y: e.clientY,
160
+ width: rect.width,
161
+ height: rect.height,
162
+ });
163
+ }
164
+ }, []);
165
+ /**
166
+ * Handles mouse wheel events on resize handles to adjust size.
167
+ */
168
+ const handleResizeWheel = useCallback((e, direction) => {
169
+ e.preventDefault();
170
+ if (!boxRef.current)
171
+ return;
172
+ const rect = boxRef.current.getBoundingClientRect();
173
+ const delta = e.deltaY > 0 ? -10 : 10;
174
+ let newWidth = boxSize.width || rect.width;
175
+ let newHeight = boxSize.height || rect.height;
176
+ if (direction.includes("right") || direction.includes("left")) {
177
+ newWidth = Math.max(300, newWidth + delta);
178
+ }
179
+ if (direction.includes("bottom") || direction.includes("top")) {
180
+ newHeight = Math.max(200, newHeight + delta);
181
+ }
182
+ setBoxSize({ width: newWidth, height: newHeight });
183
+ }, [boxSize.width, boxSize.height]);
103
184
  /**
104
- * Subscribes to mousemove and mouseup while dragging; unsubscribes otherwise.
185
+ * Subscribes to mousemove and mouseup while dragging or resizing; unsubscribes otherwise.
105
186
  * This ensures we only respond to these events when necessary.
106
187
  */
107
188
  useEffect(() => {
108
- if (isDragging) {
189
+ if (isDragging || isResizing) {
109
190
  window.addEventListener("mousemove", handleMouseMove);
110
191
  window.addEventListener("mouseup", handleMouseUp);
111
192
  }
@@ -117,7 +198,7 @@ export const DraggableBox = (props) => {
117
198
  window.removeEventListener("mousemove", handleMouseMove);
118
199
  window.removeEventListener("mouseup", handleMouseUp);
119
200
  };
120
- }, [isDragging, offset]);
201
+ }, [isDragging, isResizing, offset, resizeStart]);
121
202
  /**
122
203
  * Observes changes to the box size and repositions if part of the box
123
204
  * moves off-screen. This keeps the box fully visible upon resizing.
@@ -155,17 +236,88 @@ export const DraggableBox = (props) => {
155
236
  top: position.y,
156
237
  userSelect: "none",
157
238
  minWidth: 300,
239
+ width: boxSize.width || "auto",
240
+ height: boxSize.height || "auto",
158
241
  zIndex: 1000 + zIndexLayer,
159
242
  bgcolor: "background.paper",
160
243
  borderRadius: 2,
161
244
  p: 1,
162
245
  ...sx,
163
- }, children: [_jsx(Box, { sx: {
246
+ }, children: [_jsxs(Box, { sx: {
164
247
  height: 30,
165
248
  cursor: "move",
249
+ display: "flex",
250
+ alignItems: "center",
251
+ justifyContent: "space-between",
166
252
  ...slotSxProps?.header,
167
- }, onMouseDown: handleMouseDown, children: _jsx(Typography, { size: size, sx: {
168
- p: 0.5,
169
- ...slotSxProps?.title,
170
- }, bold: true, children: title }) }), _jsx(Box, { children: children })] }) })] }));
253
+ }, onMouseDown: handleMouseDown, children: [_jsx(Typography, { size: size, sx: {
254
+ p: 0.5,
255
+ flexGrow: 1,
256
+ ...slotSxProps?.title,
257
+ }, bold: true, children: title }), _jsx(IconButton, { size: "small", onClick: (e) => {
258
+ e.stopPropagation();
259
+ onClose();
260
+ }, onMouseDown: (e) => {
261
+ e.stopPropagation();
262
+ }, sx: {
263
+ padding: 0.5,
264
+ "&:hover": {
265
+ bgcolor: "action.hover",
266
+ },
267
+ }, children: _jsx(CloseIcon, { fontSize: "small" }) })] }), _jsx(Box, { children: children }), resizable && (_jsxs(_Fragment, { children: [_jsx(Box, { sx: {
268
+ position: "absolute",
269
+ right: 0,
270
+ top: 0,
271
+ bottom: 0,
272
+ width: 8,
273
+ cursor: "ew-resize",
274
+ "&:hover": {
275
+ bgcolor: "primary.main",
276
+ opacity: 0.3,
277
+ },
278
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "right"), onWheel: (e) => handleResizeWheel(e, "right") }), _jsx(Box, { sx: {
279
+ position: "absolute",
280
+ bottom: 0,
281
+ left: 0,
282
+ right: 0,
283
+ height: 8,
284
+ cursor: "ns-resize",
285
+ "&:hover": {
286
+ bgcolor: "primary.main",
287
+ opacity: 0.3,
288
+ },
289
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "bottom"), onWheel: (e) => handleResizeWheel(e, "bottom") }), _jsx(Box, { sx: {
290
+ position: "absolute",
291
+ bottom: 0,
292
+ right: 0,
293
+ width: 16,
294
+ height: 16,
295
+ cursor: "nwse-resize",
296
+ "&:hover": {
297
+ bgcolor: "primary.main",
298
+ opacity: 0.3,
299
+ },
300
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "bottom-right"), onWheel: (e) => handleResizeWheel(e, "bottom-right") }), _jsx(Box, { sx: {
301
+ position: "absolute",
302
+ left: 0,
303
+ top: 0,
304
+ bottom: 0,
305
+ width: 8,
306
+ cursor: "ew-resize",
307
+ "&:hover": {
308
+ bgcolor: "primary.main",
309
+ opacity: 0.3,
310
+ },
311
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "left"), onWheel: (e) => handleResizeWheel(e, "left") }), _jsx(Box, { sx: {
312
+ position: "absolute",
313
+ top: 0,
314
+ left: 0,
315
+ right: 0,
316
+ height: 8,
317
+ cursor: "ns-resize",
318
+ "&:hover": {
319
+ bgcolor: "primary.main",
320
+ opacity: 0.3,
321
+ },
322
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "top"), onWheel: (e) => handleResizeWheel(e, "top") })] }))] }) })] }));
171
323
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rnaga/wp-next-ui",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "scripts": {
5
5
  "build": "node ../../scripts/build-ui.mjs",
6
6
  "release-old": "node ../../scripts/release.mjs",