zuljaman-banner-components 1.0.7 → 1.0.9
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DraggableElement.d.ts","sourceRoot":"","sources":["../../../src/components/shared/DraggableElement.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"DraggableElement.d.ts","sourceRoot":"","sources":["../../../src/components/shared/DraggableElement.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IAGpB,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3D,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,IAAI,CAAC;IAGvB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAG1D,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAyhB5D,CAAC"}
|
|
@@ -11,12 +11,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
11
11
|
exports.DraggableElement = void 0;
|
|
12
12
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
13
13
|
const react_1 = __importDefault(require("react"));
|
|
14
|
-
const react_draggable_1 = __importDefault(require("react-draggable"));
|
|
15
14
|
const DraggableElement = ({ enabled, position, rotation, width, scale, elementId, isSelected, onPositionChange, onRotationChange, onWidthChange, onSelect, onDeselect, onRotationSnap, onDragMove, centerOrigin = false, children, }) => {
|
|
16
15
|
const [isDragging, setIsDragging] = react_1.default.useState(false);
|
|
17
16
|
const [isRotating, setIsRotating] = react_1.default.useState(false);
|
|
18
17
|
const [isResizing, setIsResizing] = react_1.default.useState(false);
|
|
19
18
|
const [resizeSide, setResizeSide] = react_1.default.useState(null);
|
|
19
|
+
const [currentPosition, setCurrentPosition] = react_1.default.useState(position);
|
|
20
20
|
const elementRef = react_1.default.useRef(null);
|
|
21
21
|
const rotatingContentRef = react_1.default.useRef(null);
|
|
22
22
|
const contentOnlyRef = react_1.default.useRef(null);
|
|
@@ -32,9 +32,13 @@ const DraggableElement = ({ enabled, position, rotation, width, scale, elementId
|
|
|
32
32
|
const mouseDownPosRef = react_1.default.useRef(null);
|
|
33
33
|
const justSelectedRef = react_1.default.useRef(false);
|
|
34
34
|
const justStoppedWithoutDragRef = react_1.default.useRef(false);
|
|
35
|
+
const dragStartPosRef = react_1.default.useRef({ x: 0, y: 0 });
|
|
35
36
|
react_1.default.useEffect(() => {
|
|
36
37
|
currentRotationRef.current = rotation;
|
|
37
38
|
}, [rotation]);
|
|
39
|
+
react_1.default.useEffect(() => {
|
|
40
|
+
setCurrentPosition(position);
|
|
41
|
+
}, [position]);
|
|
38
42
|
if (!enabled) {
|
|
39
43
|
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
|
|
40
44
|
}
|
|
@@ -151,6 +155,64 @@ const DraggableElement = ({ enabled, position, rotation, width, scale, elementId
|
|
|
151
155
|
};
|
|
152
156
|
}
|
|
153
157
|
}, [isResizing, resizeSide]);
|
|
158
|
+
// Drag handlers
|
|
159
|
+
const handleDragStart = (e) => {
|
|
160
|
+
const target = e.target;
|
|
161
|
+
if (target.closest('.rotation-handle') || target.closest('.width-handle')) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Auto-select element when starting to drag
|
|
165
|
+
if (!isSelected) {
|
|
166
|
+
onSelect(elementId);
|
|
167
|
+
}
|
|
168
|
+
hasDraggedRef.current = false;
|
|
169
|
+
dragStartPosRef.current = { x: e.clientX, y: e.clientY };
|
|
170
|
+
startPositionRef.current = { x: currentPosition.x, y: currentPosition.y };
|
|
171
|
+
setIsDragging(true);
|
|
172
|
+
};
|
|
173
|
+
react_1.default.useEffect(() => {
|
|
174
|
+
if (!isDragging)
|
|
175
|
+
return;
|
|
176
|
+
const handleDragMove = (e) => {
|
|
177
|
+
hasDraggedRef.current = true;
|
|
178
|
+
const deltaX = (e.clientX - dragStartPosRef.current.x) / scale;
|
|
179
|
+
const deltaY = (e.clientY - dragStartPosRef.current.y) / scale;
|
|
180
|
+
const newPosition = {
|
|
181
|
+
x: startPositionRef.current.x + deltaX,
|
|
182
|
+
y: startPositionRef.current.y + deltaY,
|
|
183
|
+
};
|
|
184
|
+
setCurrentPosition(newPosition);
|
|
185
|
+
if (contentOnlyRef.current && onDragMove) {
|
|
186
|
+
const elementBounds = contentOnlyRef.current.getBoundingClientRect();
|
|
187
|
+
onDragMove(elementId, elementBounds);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const handleDragEnd = () => {
|
|
191
|
+
// If we didn't actually drag, set flag to prevent onClick from toggling
|
|
192
|
+
if (!hasDraggedRef.current) {
|
|
193
|
+
justStoppedWithoutDragRef.current = true;
|
|
194
|
+
}
|
|
195
|
+
setIsDragging(false);
|
|
196
|
+
// Use callback form to get latest position
|
|
197
|
+
setCurrentPosition((pos) => {
|
|
198
|
+
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(pos);
|
|
199
|
+
return pos;
|
|
200
|
+
});
|
|
201
|
+
// Auto-capture width if not explicitly set
|
|
202
|
+
if (width === undefined && contentOnlyRef.current && onWidthChange) {
|
|
203
|
+
const currentWidth = contentOnlyRef.current.offsetWidth;
|
|
204
|
+
if (currentWidth > 0) {
|
|
205
|
+
onWidthChange(Math.round(currentWidth));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
window.addEventListener('mousemove', handleDragMove);
|
|
210
|
+
window.addEventListener('mouseup', handleDragEnd);
|
|
211
|
+
return () => {
|
|
212
|
+
window.removeEventListener('mousemove', handleDragMove);
|
|
213
|
+
window.removeEventListener('mouseup', handleDragEnd);
|
|
214
|
+
};
|
|
215
|
+
}, [isDragging, scale, onDragMove, onPositionChange, onWidthChange, width, elementId]);
|
|
154
216
|
// Selection handlers
|
|
155
217
|
const handleElementClick = (e) => {
|
|
156
218
|
// Don't toggle selection if clicking rotation or width handles
|
|
@@ -196,172 +258,143 @@ const DraggableElement = ({ enabled, position, rotation, width, scale, elementId
|
|
|
196
258
|
document.removeEventListener('click', handleClickOutside);
|
|
197
259
|
};
|
|
198
260
|
}, [isSelected, onDeselect]);
|
|
199
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
261
|
+
return ((0, jsx_runtime_1.jsx)("div", { ref: elementRef, onClick: handleElementClick, onMouseDown: (e) => {
|
|
262
|
+
// Track mouse down position for click detection
|
|
200
263
|
const target = e.target;
|
|
201
264
|
if (target.closest('.rotation-handle') || target.closest('.width-handle')) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// Auto-select element when starting to drag
|
|
205
|
-
if (!isSelected) {
|
|
206
|
-
onSelect(elementId);
|
|
207
|
-
}
|
|
208
|
-
hasDraggedRef.current = false;
|
|
209
|
-
setIsDragging(true);
|
|
210
|
-
}, onDrag: (_e, _data) => {
|
|
211
|
-
hasDraggedRef.current = true;
|
|
212
|
-
if (contentOnlyRef.current && onDragMove) {
|
|
213
|
-
const elementBounds = contentOnlyRef.current.getBoundingClientRect();
|
|
214
|
-
onDragMove(elementId, elementBounds);
|
|
215
|
-
}
|
|
216
|
-
}, onStop: (_e, data) => {
|
|
217
|
-
// If we didn't actually drag, set flag to prevent onClick from toggling
|
|
218
|
-
if (!hasDraggedRef.current) {
|
|
219
|
-
justStoppedWithoutDragRef.current = true;
|
|
265
|
+
mouseDownPosRef.current = null;
|
|
266
|
+
return;
|
|
220
267
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
268
|
+
mouseDownPosRef.current = { x: e.clientX, y: e.clientY };
|
|
269
|
+
handleDragStart(e);
|
|
270
|
+
}, onMouseUp: (e) => {
|
|
271
|
+
// Detect click (mouse up at same position as mouse down)
|
|
272
|
+
const target = e.target;
|
|
273
|
+
if (target.closest('.rotation-handle') || target.closest('.width-handle')) {
|
|
274
|
+
return;
|
|
229
275
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
if (mouseDownPosRef.current) {
|
|
245
|
-
const deltaX = Math.abs(e.clientX - mouseDownPosRef.current.x);
|
|
246
|
-
const deltaY = Math.abs(e.clientY - mouseDownPosRef.current.y);
|
|
247
|
-
// If mouse hasn't moved much (less than 5px), treat as click
|
|
248
|
-
if (deltaX < 5 && deltaY < 5) {
|
|
249
|
-
e.preventDefault();
|
|
250
|
-
e.stopPropagation();
|
|
251
|
-
if (!isSelected) {
|
|
252
|
-
onSelect(elementId);
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
// Toggle off if already selected
|
|
256
|
-
onDeselect();
|
|
257
|
-
}
|
|
258
|
-
justSelectedRef.current = true; // Mark that we just selected
|
|
276
|
+
if (mouseDownPosRef.current) {
|
|
277
|
+
const deltaX = Math.abs(e.clientX - mouseDownPosRef.current.x);
|
|
278
|
+
const deltaY = Math.abs(e.clientY - mouseDownPosRef.current.y);
|
|
279
|
+
// If mouse hasn't moved much (less than 5px), treat as click
|
|
280
|
+
if (deltaX < 5 && deltaY < 5) {
|
|
281
|
+
e.preventDefault();
|
|
282
|
+
e.stopPropagation();
|
|
283
|
+
if (!isSelected) {
|
|
284
|
+
onSelect(elementId);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// Toggle off if already selected
|
|
288
|
+
onDeselect();
|
|
259
289
|
}
|
|
260
|
-
|
|
290
|
+
justSelectedRef.current = true; // Mark that we just selected
|
|
261
291
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
292
|
+
mouseDownPosRef.current = null;
|
|
293
|
+
}
|
|
294
|
+
}, style: {
|
|
295
|
+
cursor: isDragging ? "move" : "grab",
|
|
296
|
+
opacity: isDragging || isRotating || isResizing ? 0.8 : 1,
|
|
297
|
+
transition: isDragging || isRotating || isResizing ? "none" : "opacity 0.2s ease",
|
|
298
|
+
display: "inline-block",
|
|
299
|
+
position: "relative",
|
|
300
|
+
transform: `translate(${currentPosition.x}px, ${currentPosition.y}px)`,
|
|
301
|
+
}, children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
302
|
+
transform: centerOrigin ? 'translate(-50%, -50%)' : undefined,
|
|
303
|
+
position: "relative"
|
|
304
|
+
}, children: [(isDragging || isRotating || isResizing) && ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
305
|
+
position: "absolute",
|
|
306
|
+
inset: "-8px",
|
|
307
|
+
border: "2px dashed rgba(59, 130, 246, 0.5)",
|
|
308
|
+
zIndex: 0,
|
|
309
|
+
pointerEvents: "none",
|
|
310
|
+
} })), (0, jsx_runtime_1.jsxs)("div", { ref: rotatingContentRef, style: { transform: `rotate(${rotation}deg)`, position: "relative", display: "inline-block" }, children: [isSelected && ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
311
|
+
position: "absolute",
|
|
312
|
+
inset: 0,
|
|
313
|
+
border: "4px dotted rgba(59, 130, 246, 1)",
|
|
314
|
+
zIndex: 1,
|
|
315
|
+
pointerEvents: "none",
|
|
316
|
+
} })), onRotationChange && isSelected && ((0, jsx_runtime_1.jsx)("div", { ref: blueHandleRef, className: "rotation-handle", onMouseDown: handleRotationStart, style: {
|
|
317
|
+
position: "absolute",
|
|
318
|
+
top: "-16px",
|
|
319
|
+
right: "-16px",
|
|
320
|
+
width: "32px",
|
|
321
|
+
height: "32px",
|
|
322
|
+
borderRadius: "50%",
|
|
323
|
+
backgroundColor: "rgba(59, 130, 246, 0.9)",
|
|
324
|
+
border: "2px solid white",
|
|
325
|
+
cursor: "grab",
|
|
326
|
+
display: "flex",
|
|
327
|
+
alignItems: "center",
|
|
328
|
+
justifyContent: "center",
|
|
329
|
+
fontSize: "16px",
|
|
330
|
+
lineHeight: "1",
|
|
331
|
+
color: "white",
|
|
332
|
+
zIndex: 1000,
|
|
333
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
334
|
+
transform: `rotate(${-rotation}deg)`,
|
|
335
|
+
transformOrigin: "center center",
|
|
336
|
+
}, title: "Drag to rotate", children: "\u21BB" })), onRotationChange && isSelected && ((0, jsx_runtime_1.jsx)("div", { ref: purpleIndicatorRef, style: {
|
|
337
|
+
position: "absolute",
|
|
338
|
+
top: "-16px",
|
|
339
|
+
right: "-16px",
|
|
340
|
+
width: "32px",
|
|
341
|
+
height: "32px",
|
|
342
|
+
borderRadius: "50%",
|
|
343
|
+
backgroundColor: "rgba(139, 92, 246, 0.9)",
|
|
344
|
+
border: "2px solid white",
|
|
345
|
+
display: "flex",
|
|
346
|
+
alignItems: "center",
|
|
347
|
+
justifyContent: "center",
|
|
348
|
+
fontSize: "16px",
|
|
349
|
+
lineHeight: "1",
|
|
350
|
+
color: "white",
|
|
351
|
+
zIndex: 999,
|
|
352
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
353
|
+
pointerEvents: "none",
|
|
354
|
+
}, title: "Rotation indicator", children: "\u21BB" })), isSelected && ((0, jsx_runtime_1.jsx)("div", { className: "width-handle width-handle-left", onMouseDown: (e) => handleResizeStart(e, 'left'), style: {
|
|
355
|
+
position: "absolute",
|
|
356
|
+
left: "-16px",
|
|
357
|
+
top: "50%",
|
|
358
|
+
transform: `translateY(-50%) rotate(${-rotation}deg)`,
|
|
359
|
+
transformOrigin: "center center",
|
|
360
|
+
width: "32px",
|
|
361
|
+
height: "32px",
|
|
362
|
+
borderRadius: "50%",
|
|
363
|
+
backgroundColor: "rgba(16, 185, 129, 0.9)",
|
|
364
|
+
border: "2px solid white",
|
|
365
|
+
cursor: "ew-resize",
|
|
366
|
+
display: "flex",
|
|
367
|
+
alignItems: "center",
|
|
368
|
+
justifyContent: "center",
|
|
369
|
+
fontSize: "16px",
|
|
370
|
+
lineHeight: "1",
|
|
371
|
+
color: "white",
|
|
372
|
+
zIndex: 1000,
|
|
373
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
374
|
+
}, title: "Drag to resize width", children: "\u27F7" })), isSelected && ((0, jsx_runtime_1.jsx)("div", { className: "width-handle width-handle-right", onMouseDown: (e) => handleResizeStart(e, 'right'), style: {
|
|
375
|
+
position: "absolute",
|
|
376
|
+
right: "-16px",
|
|
377
|
+
top: "50%",
|
|
378
|
+
transform: `translateY(-50%) rotate(${-rotation}deg)`,
|
|
379
|
+
transformOrigin: "center center",
|
|
380
|
+
width: "32px",
|
|
381
|
+
height: "32px",
|
|
382
|
+
borderRadius: "50%",
|
|
383
|
+
backgroundColor: "rgba(16, 185, 129, 0.9)",
|
|
384
|
+
border: "2px solid white",
|
|
385
|
+
cursor: "ew-resize",
|
|
386
|
+
display: "flex",
|
|
387
|
+
alignItems: "center",
|
|
388
|
+
justifyContent: "center",
|
|
389
|
+
fontSize: "16px",
|
|
390
|
+
lineHeight: "1",
|
|
391
|
+
color: "white",
|
|
392
|
+
zIndex: 1000,
|
|
393
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
394
|
+
}, title: "Drag to resize width", children: "\u27F7" })), (0, jsx_runtime_1.jsx)("div", { ref: contentOnlyRef, style: {
|
|
395
|
+
position: "relative",
|
|
396
|
+
zIndex: 1,
|
|
397
|
+
width: width ? `${width}px` : undefined,
|
|
398
|
+
}, children: children })] })] }) }));
|
|
366
399
|
};
|
|
367
400
|
exports.DraggableElement = DraggableElement;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuljaman-banner-components",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Shared banner components package for Next.js and AWS Lambda platforms",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -45,8 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"clsx": "^2.1.1",
|
|
47
47
|
"react": "^19.0.0",
|
|
48
|
-
"react-dom": "^19.0.0"
|
|
49
|
-
"react-draggable": "^4.5.0"
|
|
48
|
+
"react-dom": "^19.0.0"
|
|
50
49
|
},
|
|
51
50
|
"peerDependencies": {
|
|
52
51
|
"next": ">=14.0.0"
|