zuljaman-banner-components 1.0.20 → 1.0.22

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":"BannerRenderer.d.ts","sourceRoot":"","sources":["../../src/components/BannerRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAgE,MAAM,OAAO,CAAC;AAGrF,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAUvD,UAAU,mBAAmB;IAE3B,WAAW,EAAE,MAAM,CAAC;IAGpB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IAEtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAGhD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAG7B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACpE,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAG5C,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvF,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAChE;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAukBxD,CAAC"}
1
+ {"version":3,"file":"BannerRenderer.d.ts","sourceRoot":"","sources":["../../src/components/BannerRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAgE,MAAM,OAAO,CAAC;AAGrF,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAUvD,UAAU,mBAAmB;IAE3B,WAAW,EAAE,MAAM,CAAC;IAGpB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IAEtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAGhD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAG7B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACpE,oBAAoB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAG5C,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvF,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAChE;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAovBxD,CAAC"}
@@ -61,6 +61,11 @@ const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl,
61
61
  const [recalcTrigger, setRecalcTrigger] = (0, react_1.useState)(0);
62
62
  const logoRef = (0, react_1.useRef)(null);
63
63
  const copyRefs = (0, react_1.useRef)([]);
64
+ const bannerContainerRef = (0, react_1.useRef)(null);
65
+ // Live drag position for guide lines
66
+ const [liveDragPosition, setLiveDragPosition] = (0, react_1.useState)(null);
67
+ // Track if currently dragging
68
+ const [isDragging, setIsDragging] = (0, react_1.useState)(false);
64
69
  // Get substyle configuration based on bannerStyle
65
70
  const config = (0, react_1.useMemo)(() => {
66
71
  switch (bannerStyle) {
@@ -77,6 +82,8 @@ const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl,
77
82
  }, [bannerStyle, bannerSubstyle]);
78
83
  // Get style configuration
79
84
  const styleConfig = (0, styleConfig_1.getStyleConfig)(bannerStyle);
85
+ // Y-axis multiplier for STORY format (to spread elements vertically)
86
+ const yMultiplier = postType === "STORY" ? 1.42 : 1.0; // 1920/1350 ≈ 1.42
80
87
  // Trigger auto-positioning recalculation when style or substyle changes
81
88
  react_1.default.useEffect(() => {
82
89
  setRecalcTrigger(prev => prev + 1);
@@ -276,7 +283,37 @@ const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl,
276
283
  shadowIntensityMultiplier,
277
284
  ]);
278
285
  // Shared logo component
279
- const logoComponent = ((0, jsx_runtime_1.jsx)(shared_1.DraggableElement, { enabled: draggableMode, position: { x: logoTranslateX, y: logoTranslateY }, rotation: logoRotation, width: logoWidth, scale: sizeMultiplier, elementId: "logo", isSelected: selectedElement === "logo", onPositionChange: onLogoPositionChange, onRotationChange: onLogoRotationChange, onWidthChange: onLogoWidthChange, onSelect: (id) => setSelectedElement(id), onDeselect: () => setSelectedElement(null), onRotationSnap: handleRotationSnap, children: (0, jsx_runtime_1.jsx)("div", { ref: logoRef, className: "relative", style: {
286
+ const logoComponent = ((0, jsx_runtime_1.jsx)(shared_1.DraggableElement, { enabled: draggableMode, position: { x: logoTranslateX, y: logoTranslateY }, rotation: logoRotation, width: logoWidth, scale: sizeMultiplier, elementId: "logo", isSelected: selectedElement === "logo", onPositionChange: (pos) => {
287
+ // Clear dragging state when drag ends
288
+ setIsDragging(false);
289
+ setLiveDragPosition(null);
290
+ onLogoPositionChange === null || onLogoPositionChange === void 0 ? void 0 : onLogoPositionChange(pos);
291
+ }, onRotationChange: onLogoRotationChange, onWidthChange: onLogoWidthChange, onSelect: (id) => setSelectedElement(id), onDeselect: () => {
292
+ setSelectedElement(null);
293
+ setLiveDragPosition(null);
294
+ setIsDragging(false);
295
+ }, onRotationSnap: handleRotationSnap, onDragMove: (elementId, bounds) => {
296
+ // Set dragging state to true
297
+ setIsDragging(true);
298
+ // Calculate live position from element bounds
299
+ if (!bannerContainerRef.current)
300
+ return;
301
+ const bannerBounds = bannerContainerRef.current.getBoundingClientRect();
302
+ const elementCenterX = bounds.left + bounds.width / 2;
303
+ const elementCenterY = bounds.top + bounds.height / 2;
304
+ // Banner center in viewport coordinates
305
+ const bannerCenterX = bannerBounds.left + bannerBounds.width / 2;
306
+ const bannerCenterY = bannerBounds.top + bannerBounds.height / 2;
307
+ // Calculate offset from banner center (in scaled pixels)
308
+ const offsetX = (elementCenterX - bannerCenterX) / sizeMultiplier;
309
+ const offsetY = (elementCenterY - bannerCenterY) / sizeMultiplier;
310
+ // Store the live position
311
+ setLiveDragPosition({
312
+ elementId,
313
+ x: offsetX,
314
+ y: offsetY,
315
+ });
316
+ }, children: (0, jsx_runtime_1.jsx)("div", { ref: logoRef, className: "relative", style: {
280
317
  width: logoWidth ? `${logoWidth}px` : `${defaults_1.DEFAULT_LOGO_SIZE_REM * logoSizeMultiplier}rem`,
281
318
  height: logoWidth ? `${logoWidth}px` : `${defaults_1.DEFAULT_LOGO_SIZE_REM * logoSizeMultiplier}rem`,
282
319
  // Remove transform - DraggableElement already handles positioning
@@ -356,12 +393,15 @@ const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl,
356
393
  }, children: textElement })) : textElement;
357
394
  // Calculate final position: config position + auto-offset + user adjustment
358
395
  const baseX = isStyled ? configX : 0;
359
- const baseY = isStyled ? (configY + autoOffset) : 0;
396
+ const baseY = isStyled ? (configY * yMultiplier + autoOffset) : 0;
360
397
  const finalX = baseX + (copy.translateX || 0);
361
398
  const finalY = baseY + (copy.translateY || 0);
362
399
  const finalWidth = copy.width || configWidth;
363
400
  const finalRotation = (_c = copy.rotation) !== null && _c !== void 0 ? _c : (isStyled ? ((_d = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.rotation) !== null && _d !== void 0 ? _d : 0) : 0);
364
401
  return ((0, jsx_runtime_1.jsx)(shared_1.DraggableElement, { enabled: draggableMode, position: { x: finalX, y: finalY }, rotation: finalRotation, width: finalWidth, scale: sizeMultiplier, elementId: `copy-${copy.id}`, isSelected: selectedElement === `copy-${copy.id}`, centerOrigin: true, onPositionChange: (pos) => {
402
+ // Clear live drag position and dragging state when drag ends
403
+ setLiveDragPosition(null);
404
+ setIsDragging(false);
365
405
  // Subtract base position to get only user adjustment
366
406
  const adjustedPos = {
367
407
  x: pos.x - baseX,
@@ -382,7 +422,31 @@ const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl,
382
422
  if (copyIndex !== -1) {
383
423
  onCopyWidthChange === null || onCopyWidthChange === void 0 ? void 0 : onCopyWidthChange(copyIndex, w);
384
424
  }
385
- }, onSelect: (id) => setSelectedElement(id), onDeselect: () => setSelectedElement(null), onRotationSnap: handleRotationSnap, children: (0, jsx_runtime_1.jsx)("div", { ref: (el) => {
425
+ }, onSelect: (id) => setSelectedElement(id), onDeselect: () => {
426
+ setSelectedElement(null);
427
+ setLiveDragPosition(null);
428
+ }, onRotationSnap: handleRotationSnap, onDragMove: (elementId, bounds) => {
429
+ // Set dragging state to true
430
+ setIsDragging(true);
431
+ // Calculate live position from element bounds
432
+ if (!bannerContainerRef.current)
433
+ return;
434
+ const bannerBounds = bannerContainerRef.current.getBoundingClientRect();
435
+ const elementCenterX = bounds.left + bounds.width / 2;
436
+ const elementCenterY = bounds.top + bounds.height / 2;
437
+ // Banner center in viewport coordinates
438
+ const bannerCenterX = bannerBounds.left + bannerBounds.width / 2;
439
+ const bannerCenterY = bannerBounds.top + bannerBounds.height / 2;
440
+ // Calculate offset from banner center (in scaled pixels)
441
+ const offsetX = (elementCenterX - bannerCenterX) / sizeMultiplier;
442
+ const offsetY = (elementCenterY - bannerCenterY) / sizeMultiplier;
443
+ // Store the live position
444
+ setLiveDragPosition({
445
+ elementId,
446
+ x: offsetX,
447
+ y: offsetY,
448
+ });
449
+ }, children: (0, jsx_runtime_1.jsx)("div", { ref: (el) => {
386
450
  // Store ref by styleSlot for auto-positioning
387
451
  if (styleSlot === 0)
388
452
  copyRefs.current[0] = el;
@@ -395,7 +459,7 @@ const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl,
395
459
  display: copy.hidden ? 'none' : undefined,
396
460
  }, children: contentElement }) }, copy.id));
397
461
  };
398
- return ((0, jsx_runtime_1.jsx)("div", { className: "w-full h-full text-white leading-[1.05]", children: (0, jsx_runtime_1.jsxs)("div", { className: (0, clsx_1.default)("inset-0 flex flex-col items-start h-full relative isolate overflow-hidden gap-4 px-20", postType === "STORY" ? "pb-32 pt-44" : "py-20"), children: [backgroundImageUrl && ((0, jsx_runtime_1.jsx)(ImageComponent, { src: backgroundImageUrl, alt: "Background", width: 1080, height: postType === "STORY" ? 1920 : 1350, className: "object-cover absolute inset-0 w-full h-full -z-10", style: { objectFit: "cover", pointerEvents: "none" } })), noiseEnabled && ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 pointer-events-none", style: {
462
+ return ((0, jsx_runtime_1.jsx)("div", { className: "w-full h-full text-white leading-[1.05]", children: (0, jsx_runtime_1.jsxs)("div", { ref: bannerContainerRef, className: (0, clsx_1.default)("inset-0 flex flex-col items-start h-full relative isolate overflow-hidden gap-4 px-20", postType === "STORY" ? "pb-32 pt-44" : "py-20"), children: [backgroundImageUrl && ((0, jsx_runtime_1.jsx)(ImageComponent, { src: backgroundImageUrl, alt: "Background", width: 1080, height: postType === "STORY" ? 1920 : 1350, className: "object-cover absolute inset-0 w-full h-full -z-10", style: { objectFit: "cover", pointerEvents: "none" } })), noiseEnabled && ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 pointer-events-none", style: {
399
463
  opacity: Math.min(noiseIntensity / 2, 1), // Normalize 0-2 range to 0-1
400
464
  mixBlendMode: 'overlay',
401
465
  backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E")`,
@@ -403,12 +467,81 @@ const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl,
403
467
  } })), (0, jsx_runtime_1.jsx)("div", { style: shadowStyle, className: "relative z-10", "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)("div", { style: logoShadowStyle, className: "relative z-10", "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)("div", { className: "absolute z-20", style: {
404
468
  top: '50%',
405
469
  left: '50%',
406
- transform: `translate(${config.logo.x}px, ${config.logo.y}px)`,
407
- }, children: logoComponent }), (0, jsx_runtime_1.jsx)("div", { className: "absolute pointer-events-none", style: {
470
+ transform: `translate(${config.logo.x}px, ${config.logo.y * yMultiplier}px)`,
471
+ }, children: logoComponent }), draggableMode && isDragging && selectedElement && (() => {
472
+ var _a, _b;
473
+ let displayX = 0;
474
+ let displayY = 0;
475
+ if (selectedElement === 'logo') {
476
+ // Logo position
477
+ const finalX = logoTranslateX;
478
+ const finalY = logoTranslateY;
479
+ // Use live drag position if available, otherwise use final position
480
+ displayX = liveDragPosition && liveDragPosition.elementId === selectedElement
481
+ ? liveDragPosition.x
482
+ : finalX;
483
+ displayY = liveDragPosition && liveDragPosition.elementId === selectedElement
484
+ ? liveDragPosition.y
485
+ : finalY;
486
+ }
487
+ else if (selectedElement.startsWith('copy-')) {
488
+ // Copy position
489
+ const selectedCopyId = selectedElement.replace('copy-', '');
490
+ const selectedCopy = copies.find(c => c.id === selectedCopyId);
491
+ if (!selectedCopy)
492
+ return null;
493
+ // Calculate position for selected copy
494
+ const styleSlot = selectedCopy.styleSlot !== undefined ? selectedCopy.styleSlot : 0;
495
+ const isStyled = styleSlot === 0 || styleSlot === 1;
496
+ const copyConfig = styleSlot === 0
497
+ ? config.copy1
498
+ : ('copy2' in config ? config.copy2 : config.copy1);
499
+ const configX = (_a = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.x) !== null && _a !== void 0 ? _a : 0;
500
+ const configY = (_b = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.y) !== null && _b !== void 0 ? _b : 0;
501
+ const autoOffset = autoOffsets[styleSlot] || 0;
502
+ const baseX = isStyled ? configX : 0;
503
+ const baseY = isStyled ? (configY * yMultiplier + autoOffset) : 0;
504
+ const finalX = baseX + (selectedCopy.translateX || 0);
505
+ const finalY = baseY + (selectedCopy.translateY || 0);
506
+ // Use live drag position if available, otherwise use final position
507
+ displayX = liveDragPosition && liveDragPosition.elementId === selectedElement
508
+ ? liveDragPosition.x
509
+ : finalX;
510
+ displayY = liveDragPosition && liveDragPosition.elementId === selectedElement
511
+ ? liveDragPosition.y
512
+ : finalY;
513
+ }
514
+ else {
515
+ return null;
516
+ }
517
+ // Threshold for considering element "centered" (in pixels)
518
+ const CENTER_THRESHOLD = 5;
519
+ // Check if element is centered on each axis
520
+ const isCenteredHorizontally = Math.abs(displayX) <= CENTER_THRESHOLD;
521
+ const isCenteredVertically = Math.abs(displayY) <= CENTER_THRESHOLD;
522
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isCenteredHorizontally && ((0, jsx_runtime_1.jsx)("div", { className: "absolute pointer-events-none", style: {
523
+ left: '50%',
524
+ top: 0,
525
+ bottom: 0,
526
+ width: '6px',
527
+ backgroundColor: 'rgb(125, 211, 252)', // sky-300
528
+ transform: `translateX(${displayX - 3}px)`, // -3px to center the 6px line
529
+ zIndex: 5,
530
+ } })), isCenteredVertically && ((0, jsx_runtime_1.jsx)("div", { className: "absolute pointer-events-none", style: {
531
+ top: '50%',
532
+ left: 0,
533
+ right: 0,
534
+ height: '6px',
535
+ backgroundColor: 'rgb(125, 211, 252)', // sky-300
536
+ transform: `translateY(${displayY - 3}px)`, // -3px to center the 6px line
537
+ zIndex: 5,
538
+ } }))] }));
539
+ })(), (0, jsx_runtime_1.jsx)("div", { className: "absolute pointer-events-none", style: {
408
540
  top: '50%',
409
541
  left: '50%',
410
542
  width: 0,
411
- height: 0
543
+ height: 0,
544
+ zIndex: 10,
412
545
  }, children: copies.map((copy) => {
413
546
  // Get width from config for the wrapper
414
547
  const styleSlot = copy.styleSlot !== undefined ? copy.styleSlot : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuljaman-banner-components",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
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",