@rnaga/wp-next-ui 1.0.5 → 1.0.7

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
@@ -10,13 +10,17 @@
10
10
  * - size: Sets the Typography size ("small" | "medium").
11
11
  * - targetRef: Reference to an element whose relative position determines the box's initial placement.
12
12
  * - sx: Style overrides for the outer Box wrapping the content.
13
- * - slotSxProps: Style overrides for the header and title.
13
+ * - slotSxProps: Style overrides for the header, title, and border (width, color).
14
14
  */
15
15
  import React, { RefObject } from "react";
16
16
  import { SxProps } from "@mui/material";
17
17
  type SlotSxProps = {
18
18
  header?: SxProps;
19
19
  title?: SxProps;
20
+ border?: {
21
+ width?: number;
22
+ color?: string;
23
+ };
20
24
  };
21
25
  export declare const DraggableBox: (props: {
22
26
  children: React.ReactNode;
@@ -34,6 +38,7 @@ export declare const DraggableBox: (props: {
34
38
  slotSxProps?: SlotSxProps;
35
39
  zIndexLayer?: number;
36
40
  placement?: "target" | "left";
41
+ resizable?: boolean;
37
42
  }) => import("react/jsx-runtime").JSX.Element;
38
43
  export {};
39
44
  //# 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;IAChB,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,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,4CA0bA,CAAC"}
package/DraggableBox.js CHANGED
@@ -11,16 +11,17 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
11
11
  * - size: Sets the Typography size ("small" | "medium").
12
12
  * - targetRef: Reference to an element whose relative position determines the box's initial placement.
13
13
  * - sx: Style overrides for the outer Box wrapping the content.
14
- * - slotSxProps: Style overrides for the header and title.
14
+ * - slotSxProps: Style overrides for the header, title, and border (width, color).
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,17 @@ 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({
41
+ x: 0,
42
+ y: 0,
43
+ width: 0,
44
+ height: 0,
45
+ });
34
46
  /**
35
47
  * Ensures the new position is within the browser window bounds.
36
48
  * Returns null if the position would place the box partially off-screen.
@@ -46,35 +58,51 @@ export const DraggableBox = (props) => {
46
58
  };
47
59
  /**
48
60
  * Callback ref to get the DOM element for the draggable box.
49
- * Requires a targetRef to position the box relative to another element.
61
+ * Positions the box relative to a target element if provided, or centers it on screen.
50
62
  */
51
63
  const callbackRef = useCallback((ref) => {
52
- if (!ref || !targetRef?.current)
64
+ if (!ref)
53
65
  return;
54
66
  boxRef.current = ref;
55
67
  if (selfRef) {
56
68
  // If a selfRef is provided, assign the boxRef to it
57
69
  selfRef.current = ref;
58
70
  }
59
- // Calculate the referenced element’s position
60
- const rect = targetRef.current.getBoundingClientRect();
61
71
  const boxWidth = boxRef.current.offsetWidth || 0;
62
72
  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;
73
+ let newX;
74
+ let newY;
75
+ if (targetRef?.current) {
76
+ // Calculate the referenced element's position
77
+ const rect = targetRef.current.getBoundingClientRect();
78
+ // Compute initial position based on target element
79
+ newX = rect.left + left - boxWidth;
80
+ newY = rect.bottom - boxHeight / 2 + top;
81
+ // if placement is "target", x and y are relative to the target element
82
+ if (placement === "target") {
83
+ newX = rect.left;
84
+ newY = rect.top;
85
+ }
86
+ }
87
+ else {
88
+ // Center the box on screen if no targetRef is provided
89
+ newX = (window.innerWidth - boxWidth) / 2 + left;
90
+ newY = (window.innerHeight - boxHeight) / 2 + top;
70
91
  }
71
92
  // If the box goes off-screen at the bottom, adjust upward
72
93
  if (newY + boxHeight > window.innerHeight) {
73
94
  newY = window.innerHeight - boxHeight;
74
95
  }
96
+ // If the box goes off-screen at the right, adjust leftward
97
+ if (newX + boxWidth > window.innerWidth) {
98
+ newX = window.innerWidth - boxWidth;
99
+ }
100
+ // Ensure minimum position is not negative
101
+ newX = Math.max(0, newX);
102
+ newY = Math.max(0, newY);
75
103
  // Store the position state
76
104
  setPosition({ x: newX, y: newY });
77
- }, [targetRef, left, top]);
105
+ }, [targetRef, left, top, placement, selfRef]);
78
106
  /**
79
107
  * Called when the user presses the mouse button within the box header.
80
108
  * Captures the offset from the mouse position to the box's top-left corner.
@@ -91,21 +119,79 @@ export const DraggableBox = (props) => {
91
119
  * Updates the box position while respecting window bounds.
92
120
  */
93
121
  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);
122
+ if (isDragging && boxRef.current) {
123
+ const { offsetWidth, offsetHeight } = boxRef.current;
124
+ const newPos = clampPosition(e.clientX - offset.x, e.clientY - offset.y, offsetWidth, offsetHeight);
125
+ if (newPos)
126
+ setPosition(newPos);
127
+ }
128
+ if (isResizing && boxRef.current) {
129
+ const deltaX = e.clientX - resizeStart.x;
130
+ const deltaY = e.clientY - resizeStart.y;
131
+ let newWidth = resizeStart.width;
132
+ let newHeight = resizeStart.height;
133
+ if (isResizing.includes("right")) {
134
+ newWidth = Math.max(300, resizeStart.width + deltaX);
135
+ }
136
+ if (isResizing.includes("left")) {
137
+ newWidth = Math.max(300, resizeStart.width - deltaX);
138
+ }
139
+ if (isResizing.includes("bottom")) {
140
+ newHeight = Math.max(200, resizeStart.height + deltaY);
141
+ }
142
+ if (isResizing.includes("top")) {
143
+ newHeight = Math.max(200, resizeStart.height - deltaY);
144
+ }
145
+ setBoxSize({ width: newWidth, height: newHeight });
146
+ }
100
147
  };
101
148
  // Called when the mouse is released. Ends the dragging session.
102
- const handleMouseUp = () => setIsDragging(false);
149
+ const handleMouseUp = () => {
150
+ setIsDragging(false);
151
+ setIsResizing(null);
152
+ };
153
+ /**
154
+ * Called when the user presses the mouse button on a resize handle.
155
+ * Captures the initial state for resizing.
156
+ */
157
+ const handleResizeMouseDown = useCallback((e, direction) => {
158
+ e.stopPropagation();
159
+ setIsResizing(direction);
160
+ const rect = boxRef.current?.getBoundingClientRect();
161
+ if (rect) {
162
+ setResizeStart({
163
+ x: e.clientX,
164
+ y: e.clientY,
165
+ width: rect.width,
166
+ height: rect.height,
167
+ });
168
+ }
169
+ }, []);
170
+ /**
171
+ * Handles mouse wheel events on resize handles to adjust size.
172
+ */
173
+ const handleResizeWheel = useCallback((e, direction) => {
174
+ e.preventDefault();
175
+ if (!boxRef.current)
176
+ return;
177
+ const rect = boxRef.current.getBoundingClientRect();
178
+ const delta = e.deltaY > 0 ? -10 : 10;
179
+ let newWidth = boxSize.width || rect.width;
180
+ let newHeight = boxSize.height || rect.height;
181
+ if (direction.includes("right") || direction.includes("left")) {
182
+ newWidth = Math.max(300, newWidth + delta);
183
+ }
184
+ if (direction.includes("bottom") || direction.includes("top")) {
185
+ newHeight = Math.max(200, newHeight + delta);
186
+ }
187
+ setBoxSize({ width: newWidth, height: newHeight });
188
+ }, [boxSize.width, boxSize.height]);
103
189
  /**
104
- * Subscribes to mousemove and mouseup while dragging; unsubscribes otherwise.
190
+ * Subscribes to mousemove and mouseup while dragging or resizing; unsubscribes otherwise.
105
191
  * This ensures we only respond to these events when necessary.
106
192
  */
107
193
  useEffect(() => {
108
- if (isDragging) {
194
+ if (isDragging || isResizing) {
109
195
  window.addEventListener("mousemove", handleMouseMove);
110
196
  window.addEventListener("mouseup", handleMouseUp);
111
197
  }
@@ -117,7 +203,7 @@ export const DraggableBox = (props) => {
117
203
  window.removeEventListener("mousemove", handleMouseMove);
118
204
  window.removeEventListener("mouseup", handleMouseUp);
119
205
  };
120
- }, [isDragging, offset]);
206
+ }, [isDragging, isResizing, offset, resizeStart]);
121
207
  /**
122
208
  * Observes changes to the box size and repositions if part of the box
123
209
  * moves off-screen. This keeps the box fully visible upon resizing.
@@ -155,17 +241,91 @@ export const DraggableBox = (props) => {
155
241
  top: position.y,
156
242
  userSelect: "none",
157
243
  minWidth: 300,
244
+ width: boxSize.width || "auto",
245
+ height: boxSize.height || "auto",
158
246
  zIndex: 1000 + zIndexLayer,
159
247
  bgcolor: "background.paper",
160
- borderRadius: 2,
248
+ borderRadius: 1,
161
249
  p: 1,
250
+ border: `${slotSxProps?.border?.width ?? 1}px solid`,
251
+ borderColor: slotSxProps?.border?.color ?? "grey.500",
252
+ transform: "translateZ(0)",
162
253
  ...sx,
163
- }, children: [_jsx(Box, { sx: {
254
+ }, children: [_jsxs(Box, { sx: {
164
255
  height: 30,
165
256
  cursor: "move",
257
+ display: "flex",
258
+ alignItems: "center",
259
+ justifyContent: "space-between",
166
260
  ...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 })] }) })] }));
261
+ }, onMouseDown: handleMouseDown, children: [_jsx(Typography, { size: size, sx: {
262
+ p: 0.5,
263
+ flexGrow: 1,
264
+ ...slotSxProps?.title,
265
+ }, bold: true, children: title }), _jsx(IconButton, { size: "small", onClick: (e) => {
266
+ e.stopPropagation();
267
+ onClose();
268
+ }, onMouseDown: (e) => {
269
+ e.stopPropagation();
270
+ }, sx: {
271
+ padding: 0.5,
272
+ "&:hover": {
273
+ bgcolor: "action.hover",
274
+ },
275
+ }, children: _jsx(CloseIcon, { fontSize: "small" }) })] }), _jsx(Box, { children: children }), resizable && (_jsxs(_Fragment, { children: [_jsx(Box, { sx: {
276
+ position: "absolute",
277
+ right: 0,
278
+ top: 0,
279
+ bottom: 0,
280
+ width: 8,
281
+ cursor: "ew-resize",
282
+ "&:hover": {
283
+ bgcolor: "primary.main",
284
+ opacity: 0.3,
285
+ },
286
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "right"), onWheel: (e) => handleResizeWheel(e, "right") }), _jsx(Box, { sx: {
287
+ position: "absolute",
288
+ bottom: 0,
289
+ left: 0,
290
+ right: 0,
291
+ height: 8,
292
+ cursor: "ns-resize",
293
+ "&:hover": {
294
+ bgcolor: "primary.main",
295
+ opacity: 0.3,
296
+ },
297
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "bottom"), onWheel: (e) => handleResizeWheel(e, "bottom") }), _jsx(Box, { sx: {
298
+ position: "absolute",
299
+ bottom: 0,
300
+ right: 0,
301
+ width: 16,
302
+ height: 16,
303
+ cursor: "nwse-resize",
304
+ "&:hover": {
305
+ bgcolor: "primary.main",
306
+ opacity: 0.3,
307
+ },
308
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "bottom-right"), onWheel: (e) => handleResizeWheel(e, "bottom-right") }), _jsx(Box, { sx: {
309
+ position: "absolute",
310
+ left: 0,
311
+ top: 0,
312
+ bottom: 0,
313
+ width: 8,
314
+ cursor: "ew-resize",
315
+ "&:hover": {
316
+ bgcolor: "primary.main",
317
+ opacity: 0.3,
318
+ },
319
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "left"), onWheel: (e) => handleResizeWheel(e, "left") }), _jsx(Box, { sx: {
320
+ position: "absolute",
321
+ top: 0,
322
+ left: 0,
323
+ right: 0,
324
+ height: 8,
325
+ cursor: "ns-resize",
326
+ "&:hover": {
327
+ bgcolor: "primary.main",
328
+ opacity: 0.3,
329
+ },
330
+ }, onMouseDown: (e) => handleResizeMouseDown(e, "top"), onWheel: (e) => handleResizeWheel(e, "top") })] }))] }) })] }));
171
331
  };
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.7",
4
4
  "scripts": {
5
5
  "build": "node ../../scripts/build-ui.mjs",
6
6
  "release-old": "node ../../scripts/release.mjs",