zuljaman-banner-components 1.0.23 → 1.0.24
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/README.md +228 -131
- package/dist/components/BannerRenderer/BannerRenderer.d.ts +8 -0
- package/dist/components/BannerRenderer/BannerRenderer.d.ts.map +1 -0
- package/dist/components/BannerRenderer/BannerRenderer.js +325 -0
- package/dist/components/BannerRenderer/components/CopyElement.d.ts +62 -0
- package/dist/components/BannerRenderer/components/CopyElement.d.ts.map +1 -0
- package/dist/components/BannerRenderer/components/CopyElement.js +220 -0
- package/dist/components/BannerRenderer/components/InteractiveLines.d.ts +26 -0
- package/dist/components/BannerRenderer/components/InteractiveLines.d.ts.map +1 -0
- package/dist/components/BannerRenderer/components/InteractiveLines.js +172 -0
- package/dist/components/BannerRenderer/components/LogoElement.d.ts +55 -0
- package/dist/components/BannerRenderer/components/LogoElement.d.ts.map +1 -0
- package/dist/components/BannerRenderer/components/LogoElement.js +53 -0
- package/dist/components/BannerRenderer/components/VisualGuides.d.ts +43 -0
- package/dist/components/BannerRenderer/components/VisualGuides.d.ts.map +1 -0
- package/dist/components/BannerRenderer/components/VisualGuides.js +110 -0
- package/dist/components/BannerRenderer/components/index.d.ts +12 -0
- package/dist/components/BannerRenderer/components/index.d.ts.map +1 -0
- package/dist/components/BannerRenderer/components/index.js +14 -0
- package/dist/components/BannerRenderer/constants.d.ts +15 -0
- package/dist/components/BannerRenderer/constants.d.ts.map +1 -0
- package/dist/components/BannerRenderer/constants.js +36 -0
- package/dist/components/BannerRenderer/hooks/index.d.ts +14 -0
- package/dist/components/BannerRenderer/hooks/index.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/index.js +16 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/debugPositions.d.ts +30 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/debugPositions.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/debugPositions.js +87 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/index.d.ts +13 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/index.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/index.js +21 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAnchorEdgeLocking.d.ts +71 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAnchorEdgeLocking.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAnchorEdgeLocking.js +151 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAutoPositioningMain.d.ts +66 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAutoPositioningMain.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAutoPositioningMain.js +332 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useChainPositioning.d.ts +61 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useChainPositioning.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useChainPositioning.js +180 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useHeightCompensation.d.ts +60 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useHeightCompensation.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning/useHeightCompensation.js +178 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning.d.ts +8 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useAutoPositioning.js +12 -0
- package/dist/components/BannerRenderer/hooks/useDragSnap.d.ts +30 -0
- package/dist/components/BannerRenderer/hooks/useDragSnap.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useDragSnap.js +90 -0
- package/dist/components/BannerRenderer/hooks/useElementRefs.d.ts +22 -0
- package/dist/components/BannerRenderer/hooks/useElementRefs.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useElementRefs.js +70 -0
- package/dist/components/BannerRenderer/hooks/useLineDrawing.d.ts +40 -0
- package/dist/components/BannerRenderer/hooks/useLineDrawing.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useLineDrawing.js +198 -0
- package/dist/components/BannerRenderer/hooks/useProximityDetection.d.ts +43 -0
- package/dist/components/BannerRenderer/hooks/useProximityDetection.d.ts.map +1 -0
- package/dist/components/BannerRenderer/hooks/useProximityDetection.js +491 -0
- package/dist/components/BannerRenderer/index.d.ts +6 -0
- package/dist/components/BannerRenderer/index.d.ts.map +1 -0
- package/dist/components/BannerRenderer/index.js +8 -0
- package/dist/components/{BannerRenderer.d.ts → BannerRenderer/types.d.ts} +29 -8
- package/dist/components/BannerRenderer/types.d.ts.map +1 -0
- package/dist/components/BannerRenderer/types.js +5 -0
- package/dist/components/BannerRenderer/utils/alignmentUtils.d.ts +38 -0
- package/dist/components/BannerRenderer/utils/alignmentUtils.d.ts.map +1 -0
- package/dist/components/BannerRenderer/utils/alignmentUtils.js +138 -0
- package/dist/components/BannerRenderer/utils/elementCheckUtils.d.ts +22 -0
- package/dist/components/BannerRenderer/utils/elementCheckUtils.d.ts.map +1 -0
- package/dist/components/BannerRenderer/utils/elementCheckUtils.js +37 -0
- package/dist/components/BannerRenderer/utils/elementIdUtils.d.ts +25 -0
- package/dist/components/BannerRenderer/utils/elementIdUtils.d.ts.map +1 -0
- package/dist/components/BannerRenderer/utils/elementIdUtils.js +56 -0
- package/dist/components/BannerRenderer/utils/fontUtils.d.ts +12 -0
- package/dist/components/BannerRenderer/utils/fontUtils.d.ts.map +1 -0
- package/dist/components/BannerRenderer/utils/fontUtils.js +26 -0
- package/dist/components/BannerRenderer/utils/graphUtils.d.ts +54 -0
- package/dist/components/BannerRenderer/utils/graphUtils.d.ts.map +1 -0
- package/dist/components/BannerRenderer/utils/graphUtils.js +138 -0
- package/dist/components/BannerRenderer/utils/index.d.ts +12 -0
- package/dist/components/BannerRenderer/utils/index.d.ts.map +1 -0
- package/dist/components/BannerRenderer/utils/index.js +27 -0
- package/dist/components/BannerRenderer/utils/snapUtils.d.ts +38 -0
- package/dist/components/BannerRenderer/utils/snapUtils.d.ts.map +1 -0
- package/dist/components/BannerRenderer/utils/snapUtils.js +109 -0
- package/dist/components/BannerVisor.d.ts.map +1 -1
- package/dist/components/BannerVisor.js +8 -1
- package/dist/components/index.js +1 -1
- package/dist/components/shared/DraggableElement.d.ts +11 -0
- package/dist/components/shared/DraggableElement.d.ts.map +1 -1
- package/dist/components/shared/DraggableElement.js +47 -51
- package/dist/components/styles/Style1/substyleConfig.d.ts.map +1 -1
- package/dist/components/styles/Style1/substyleConfig.js +53 -54
- package/dist/components/styles/Style2/substyleConfig.js +78 -78
- package/dist/components/styles/Style3/substyleConfig.d.ts.map +1 -1
- package/dist/components/styles/Style3/substyleConfig.js +40 -37
- package/dist/components/styles/Style4/substyleConfig.js +57 -57
- package/dist/components/styles/types/substyleTypes.d.ts +32 -15
- package/dist/components/styles/types/substyleTypes.d.ts.map +1 -1
- package/dist/components/styles/utils/chainValidation.d.ts +41 -0
- package/dist/components/styles/utils/chainValidation.d.ts.map +1 -0
- package/dist/components/styles/utils/chainValidation.js +148 -0
- package/dist/components/styles/utils/positioningUtils.d.ts +207 -11
- package/dist/components/styles/utils/positioningUtils.d.ts.map +1 -1
- package/dist/components/styles/utils/positioningUtils.js +520 -19
- package/dist/constants/characterLimits.d.ts +4 -16
- package/dist/constants/characterLimits.d.ts.map +1 -1
- package/dist/constants/characterLimits.js +28 -26
- package/dist/constants/styleConfigs.js +6 -6
- package/dist/styleConfig.d.ts +4 -4
- package/dist/styleConfig.d.ts.map +1 -1
- package/dist/styleConfig.js +8 -16
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/components/BannerRenderer.d.ts.map +0 -1
- package/dist/components/BannerRenderer.js +0 -559
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BannerRenderer component - Generic platform-agnostic banner renderer
|
|
4
|
+
* Unified component that handles all banner styles based on configuration
|
|
5
|
+
*/
|
|
6
|
+
"use client";
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.BannerRenderer = void 0;
|
|
45
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
46
|
+
const react_1 = __importStar(require("react"));
|
|
47
|
+
const clsx_1 = __importDefault(require("clsx"));
|
|
48
|
+
const shadowUtils_1 = require("../../styles/shadowUtils");
|
|
49
|
+
const styleConfig_1 = require("../../styleConfig");
|
|
50
|
+
const substyleConfig_1 = require("../styles/Style1/substyleConfig");
|
|
51
|
+
const substyleConfig_2 = require("../styles/Style2/substyleConfig");
|
|
52
|
+
const substyleConfig_3 = require("../styles/Style3/substyleConfig");
|
|
53
|
+
const substyleConfig_4 = require("../styles/Style4/substyleConfig");
|
|
54
|
+
const hooks_1 = require("./hooks");
|
|
55
|
+
const components_1 = require("./components");
|
|
56
|
+
// Note: marching ants animation is auto-injected by constants.ts import
|
|
57
|
+
const BannerRenderer = ({ bannerStyle, copies = [], bannerSubstyle = 1, logoUrl, sizeMultiplier = 1.0, logoSizeMultiplier = 1.0, overlayIntensityMultiplier: _overlayIntensityMultiplier = 1.0, shadowIntensityMultiplier = 1.0, backgroundImageUrl, postType, ImageComponent, logoTranslateX = 0, logoTranslateY = 0, draggableMode = false, creationMode = false, linkingModeActive = false, onDebugPositions, onApplyAutoPositioning, onConnectionsDeleted, onLineGapsChange, onLogoPositionChange, logoRotation = 0, onLogoRotationChange, logoWidth, onLogoWidthChange, onCopyPositionChange, onCopyRotationChange, onCopyWidthChange, textShadowEnabled, textShadowSize, textShadowIntensity, logoShadowEnabled, logoShadowSize, logoShadowIntensity, noiseEnabled, noiseIntensity = 1.0, fontFamily, autoPositioningOverride, }) => {
|
|
58
|
+
const [selectedElement, setSelectedElement] = (0, react_1.useState)(null);
|
|
59
|
+
// Element refs
|
|
60
|
+
const logoRef = (0, react_1.useRef)(null);
|
|
61
|
+
const copyRefs = (0, react_1.useRef)([]);
|
|
62
|
+
const bannerContainerRef = (0, react_1.useRef)(null);
|
|
63
|
+
// Element reference helpers from custom hook
|
|
64
|
+
const { getElementRef, areElementsOverlapping, areVerticallyAligned } = (0, hooks_1.useElementRefs)({
|
|
65
|
+
logoRef,
|
|
66
|
+
copyRefs,
|
|
67
|
+
copies,
|
|
68
|
+
});
|
|
69
|
+
// Drag snap and alignment helpers from custom hook
|
|
70
|
+
const { handleRotationSnap, handlePositionSnap, calculateAlignments } = (0, hooks_1.useDragSnap)({
|
|
71
|
+
logoRef,
|
|
72
|
+
copyRefs,
|
|
73
|
+
bannerContainerRef,
|
|
74
|
+
copies,
|
|
75
|
+
sizeMultiplier,
|
|
76
|
+
});
|
|
77
|
+
// Config key for auto-resetting hooks when style/substyle changes
|
|
78
|
+
// This allows hooks to self-reset without requiring consumer to use key prop
|
|
79
|
+
const configKey = `${bannerStyle}-${bannerSubstyle}`;
|
|
80
|
+
// Get autoPositioningConfig early (needed for useLineDrawing to initialize completedLines)
|
|
81
|
+
const autoPositioningConfigForLines = (0, react_1.useMemo)(() => {
|
|
82
|
+
let baseConfig;
|
|
83
|
+
switch (bannerStyle) {
|
|
84
|
+
case 2:
|
|
85
|
+
baseConfig = (0, substyleConfig_2.getSubstyleConfig)(bannerSubstyle);
|
|
86
|
+
break;
|
|
87
|
+
case 3:
|
|
88
|
+
baseConfig = (0, substyleConfig_3.getSubstyleConfig)(bannerSubstyle);
|
|
89
|
+
break;
|
|
90
|
+
case 4:
|
|
91
|
+
baseConfig = (0, substyleConfig_4.getSubstyleConfig)(bannerSubstyle);
|
|
92
|
+
break;
|
|
93
|
+
case 1:
|
|
94
|
+
default:
|
|
95
|
+
baseConfig = (0, substyleConfig_1.getSubstyleConfig)(bannerSubstyle);
|
|
96
|
+
}
|
|
97
|
+
// Apply override if provided
|
|
98
|
+
if (autoPositioningOverride === null || autoPositioningOverride === void 0 ? void 0 : autoPositioningOverride.config) {
|
|
99
|
+
return autoPositioningOverride.config;
|
|
100
|
+
}
|
|
101
|
+
return baseConfig.autoPositioningConfig;
|
|
102
|
+
}, [bannerStyle, bannerSubstyle, autoPositioningOverride]);
|
|
103
|
+
// Line drawing state and handlers from custom hook
|
|
104
|
+
const { drawingFrom, drawingMousePos, completedLines, manualLines, setCompletedLines, setManualLines, handleToggleAutoPositioning, handleMouseMove, handleContainerClick, handleCompleteLineTo, convertToStyleSlotId, } = (0, hooks_1.useLineDrawing)({
|
|
105
|
+
bannerContainerRef,
|
|
106
|
+
copies,
|
|
107
|
+
sizeMultiplier,
|
|
108
|
+
creationMode,
|
|
109
|
+
areElementsOverlapping,
|
|
110
|
+
areVerticallyAligned,
|
|
111
|
+
autoPositioningConfig: autoPositioningConfigForLines,
|
|
112
|
+
configKey,
|
|
113
|
+
});
|
|
114
|
+
// Live drag position for guide lines
|
|
115
|
+
const [liveDragPosition, setLiveDragPosition] = (0, react_1.useState)(null);
|
|
116
|
+
// Track if currently dragging
|
|
117
|
+
const [isDragging, setIsDragging] = (0, react_1.useState)(false);
|
|
118
|
+
// Track which line is being hovered
|
|
119
|
+
const [hoveredLine, setHoveredLine] = (0, react_1.useState)(null);
|
|
120
|
+
// Store gap values for each line (preserved when link is created)
|
|
121
|
+
const [lineGaps, setLineGaps] = (0, react_1.useState)(new Map());
|
|
122
|
+
// Expose lineGaps to parent via callback (using ref to avoid infinite loops)
|
|
123
|
+
const prevLineGapsRef = (0, react_1.useRef)('');
|
|
124
|
+
(0, react_1.useEffect)(() => {
|
|
125
|
+
if (onLineGapsChange && lineGaps.size > 0) {
|
|
126
|
+
const gapsObject = {};
|
|
127
|
+
lineGaps.forEach((value, key) => {
|
|
128
|
+
gapsObject[key] = value;
|
|
129
|
+
});
|
|
130
|
+
// Only call callback if gaps actually changed
|
|
131
|
+
const gapsJson = JSON.stringify(gapsObject);
|
|
132
|
+
if (gapsJson !== prevLineGapsRef.current) {
|
|
133
|
+
prevLineGapsRef.current = gapsJson;
|
|
134
|
+
onLineGapsChange(gapsObject);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}, [lineGaps, onLineGapsChange]);
|
|
138
|
+
// Proximity detection from custom hook
|
|
139
|
+
const { proximityLines, setProximityLines, detectProximityLines, calculateProximityLines, } = (0, hooks_1.useProximityDetection)({
|
|
140
|
+
logoRef,
|
|
141
|
+
copyRefs,
|
|
142
|
+
bannerContainerRef,
|
|
143
|
+
copies,
|
|
144
|
+
sizeMultiplier,
|
|
145
|
+
creationMode,
|
|
146
|
+
manualLines,
|
|
147
|
+
completedLines,
|
|
148
|
+
setCompletedLines,
|
|
149
|
+
setLineGaps,
|
|
150
|
+
getElementRef,
|
|
151
|
+
});
|
|
152
|
+
// Alignment lines when dragging
|
|
153
|
+
const [alignmentLines, setAlignmentLines] = (0, react_1.useState)([]);
|
|
154
|
+
// Get substyle configuration based on bannerStyle (needed before useAutoPositioning)
|
|
155
|
+
const config = (0, react_1.useMemo)(() => {
|
|
156
|
+
var _a, _b;
|
|
157
|
+
let baseConfig;
|
|
158
|
+
switch (bannerStyle) {
|
|
159
|
+
case 2:
|
|
160
|
+
baseConfig = (0, substyleConfig_2.getSubstyleConfig)(bannerSubstyle);
|
|
161
|
+
break;
|
|
162
|
+
case 3:
|
|
163
|
+
baseConfig = (0, substyleConfig_3.getSubstyleConfig)(bannerSubstyle);
|
|
164
|
+
break;
|
|
165
|
+
case 4:
|
|
166
|
+
baseConfig = (0, substyleConfig_4.getSubstyleConfig)(bannerSubstyle);
|
|
167
|
+
break;
|
|
168
|
+
case 1:
|
|
169
|
+
default:
|
|
170
|
+
baseConfig = (0, substyleConfig_1.getSubstyleConfig)(bannerSubstyle);
|
|
171
|
+
}
|
|
172
|
+
// Apply auto-positioning override if provided
|
|
173
|
+
if (autoPositioningOverride) {
|
|
174
|
+
const result = {
|
|
175
|
+
...baseConfig,
|
|
176
|
+
autoPositioning: autoPositioningOverride.enabled,
|
|
177
|
+
autoPositioningConfig: autoPositioningOverride.config,
|
|
178
|
+
gapRem: (_a = autoPositioningOverride.gapRem) !== null && _a !== void 0 ? _a : baseConfig.gapRem,
|
|
179
|
+
copies: (_b = autoPositioningOverride.copies) !== null && _b !== void 0 ? _b : baseConfig.copies,
|
|
180
|
+
};
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
return baseConfig;
|
|
184
|
+
}, [bannerStyle, bannerSubstyle, autoPositioningOverride]);
|
|
185
|
+
// Get style configuration
|
|
186
|
+
const styleConfig = (0, styleConfig_1.getStyleConfig)(bannerStyle);
|
|
187
|
+
// Y-axis multiplier for STORY format (to spread elements vertically)
|
|
188
|
+
const yMultiplier = postType === "STORY" ? 1.42 : 1.0; // 1920/1350 ≈ 1.42
|
|
189
|
+
// Auto-positioning state and calculations from custom hook
|
|
190
|
+
const { autoOffsets, anchorCompensation, lineRecalcTrigger, derivedAutoConfig, debugPositions, applyAutoPositioningConfig, } = (0, hooks_1.useAutoPositioning)({
|
|
191
|
+
logoRef,
|
|
192
|
+
copyRefs,
|
|
193
|
+
bannerContainerRef,
|
|
194
|
+
copies,
|
|
195
|
+
sizeMultiplier,
|
|
196
|
+
creationMode,
|
|
197
|
+
completedLines,
|
|
198
|
+
manualLines,
|
|
199
|
+
lineGaps,
|
|
200
|
+
setCompletedLines,
|
|
201
|
+
setManualLines,
|
|
202
|
+
setLineGaps,
|
|
203
|
+
config,
|
|
204
|
+
autoPositioningOverride,
|
|
205
|
+
logoTranslateX,
|
|
206
|
+
logoTranslateY,
|
|
207
|
+
logoRotation,
|
|
208
|
+
logoWidth,
|
|
209
|
+
bannerStyle,
|
|
210
|
+
onApplyAutoPositioning,
|
|
211
|
+
onCopyPositionChange,
|
|
212
|
+
onConnectionsDeleted,
|
|
213
|
+
exposeDebugFunctions: !!onDebugPositions,
|
|
214
|
+
areElementsOverlapping,
|
|
215
|
+
areVerticallyAligned,
|
|
216
|
+
configKey,
|
|
217
|
+
});
|
|
218
|
+
// Shadow calculations using style configuration
|
|
219
|
+
const { shadowStyle, logoShadowStyle } = (0, react_1.useMemo)(() => {
|
|
220
|
+
var _a, _b;
|
|
221
|
+
// Get shadow defaults from style config (or use fallback values)
|
|
222
|
+
const textShadowConfig = ((_a = styleConfig.shadows) === null || _a === void 0 ? void 0 : _a.textShadow) || {
|
|
223
|
+
enabled: true,
|
|
224
|
+
size: 70,
|
|
225
|
+
intensity: 0.85,
|
|
226
|
+
direction: 'bottom',
|
|
227
|
+
};
|
|
228
|
+
const logoShadowConfig = ((_b = styleConfig.shadows) === null || _b === void 0 ? void 0 : _b.logoShadow) || {
|
|
229
|
+
enabled: true,
|
|
230
|
+
size: 150,
|
|
231
|
+
intensity: 0.375,
|
|
232
|
+
direction: 'top-left',
|
|
233
|
+
};
|
|
234
|
+
// Use prop overrides if provided, otherwise use config values
|
|
235
|
+
const effectiveTextShadowEnabled = textShadowEnabled !== null && textShadowEnabled !== void 0 ? textShadowEnabled : textShadowConfig.enabled;
|
|
236
|
+
const effectiveTextShadowSize = textShadowSize !== null && textShadowSize !== void 0 ? textShadowSize : textShadowConfig.size;
|
|
237
|
+
const effectiveTextShadowIntensity = textShadowIntensity !== null && textShadowIntensity !== void 0 ? textShadowIntensity : textShadowConfig.intensity;
|
|
238
|
+
const effectiveLogoShadowEnabled = logoShadowEnabled !== null && logoShadowEnabled !== void 0 ? logoShadowEnabled : logoShadowConfig.enabled;
|
|
239
|
+
const effectiveLogoShadowSize = logoShadowSize !== null && logoShadowSize !== void 0 ? logoShadowSize : logoShadowConfig.size;
|
|
240
|
+
const effectiveLogoShadowIntensity = logoShadowIntensity !== null && logoShadowIntensity !== void 0 ? logoShadowIntensity : logoShadowConfig.intensity;
|
|
241
|
+
// Generate shadow styles only if enabled
|
|
242
|
+
const shadowStyle = effectiveTextShadowEnabled
|
|
243
|
+
? (0, shadowUtils_1.createAbstractShadowStyle)({
|
|
244
|
+
direction: textShadowConfig.direction,
|
|
245
|
+
size: `${effectiveTextShadowSize}%`,
|
|
246
|
+
intensity: effectiveTextShadowIntensity * shadowIntensityMultiplier,
|
|
247
|
+
})
|
|
248
|
+
: {};
|
|
249
|
+
const logoShadowStyle = effectiveLogoShadowEnabled
|
|
250
|
+
? (0, shadowUtils_1.createAbstractShadowStyle)({
|
|
251
|
+
direction: logoShadowConfig.direction,
|
|
252
|
+
size: `${effectiveLogoShadowSize}%`,
|
|
253
|
+
intensity: effectiveLogoShadowIntensity * shadowIntensityMultiplier,
|
|
254
|
+
})
|
|
255
|
+
: {};
|
|
256
|
+
return { shadowStyle, logoShadowStyle };
|
|
257
|
+
}, [
|
|
258
|
+
styleConfig.shadows,
|
|
259
|
+
textShadowEnabled,
|
|
260
|
+
textShadowSize,
|
|
261
|
+
textShadowIntensity,
|
|
262
|
+
logoShadowEnabled,
|
|
263
|
+
logoShadowSize,
|
|
264
|
+
logoShadowIntensity,
|
|
265
|
+
shadowIntensityMultiplier,
|
|
266
|
+
]);
|
|
267
|
+
// ===== DETAILED POSITIONING DEBUG LOGGING =====
|
|
268
|
+
react_1.default.useEffect(() => {
|
|
269
|
+
// Log detailed positioning information for all copies
|
|
270
|
+
const positioningDetails = copies.map((copy, idx) => {
|
|
271
|
+
var _a, _b, _c;
|
|
272
|
+
const styleSlot = copy.styleSlot !== undefined ? copy.styleSlot : idx;
|
|
273
|
+
const copyConfig = ((_a = config.copies) === null || _a === void 0 ? void 0 : _a[styleSlot]) || ((_b = config.copies) === null || _b === void 0 ? void 0 : _b[0]);
|
|
274
|
+
const configY = (_c = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.y) !== null && _c !== void 0 ? _c : 0;
|
|
275
|
+
const autoOffset = autoOffsets[styleSlot] || 0;
|
|
276
|
+
const baseY = configY * yMultiplier + autoOffset;
|
|
277
|
+
const effectiveTranslateY = copy.translateY || 0;
|
|
278
|
+
const finalY = baseY + effectiveTranslateY;
|
|
279
|
+
return {
|
|
280
|
+
index: idx,
|
|
281
|
+
styleSlot,
|
|
282
|
+
text: copy.text.substring(0, 30) + '...',
|
|
283
|
+
configY,
|
|
284
|
+
yMultiplier,
|
|
285
|
+
autoOffset,
|
|
286
|
+
baseY,
|
|
287
|
+
translateY: copy.translateY,
|
|
288
|
+
effectiveTranslateY,
|
|
289
|
+
finalY: Math.round(finalY),
|
|
290
|
+
translateX: copy.translateX,
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
console.log('📐 POSITIONING DETAILS:', Date.now(), JSON.stringify(positioningDetails, null, 2));
|
|
294
|
+
}, [copies, autoOffsets, config, yMultiplier]);
|
|
295
|
+
// Shared logo component (extracted to LogoElement)
|
|
296
|
+
const logoComponent = ((0, jsx_runtime_1.jsx)(components_1.LogoElement, { logoTranslateX: logoTranslateX, logoTranslateY: logoTranslateY, logoRotation: logoRotation, logoWidth: logoWidth, logoUrl: logoUrl, logoSizeMultiplier: logoSizeMultiplier, sizeMultiplier: sizeMultiplier, draggableMode: draggableMode, creationMode: creationMode, linkingModeActive: linkingModeActive, selectedElement: selectedElement, completedLines: completedLines, drawingFrom: drawingFrom, logoRef: logoRef, bannerContainerRef: bannerContainerRef, ImageComponent: ImageComponent, onLogoPositionChange: onLogoPositionChange, onLogoRotationChange: onLogoRotationChange, onLogoWidthChange: onLogoWidthChange, setSelectedElement: setSelectedElement, setIsDragging: setIsDragging, setLiveDragPosition: setLiveDragPosition, setAlignmentLines: setAlignmentLines, setProximityLines: setProximityLines, handleToggleAutoPositioning: handleToggleAutoPositioning, handleCompleteLineTo: handleCompleteLineTo, handleRotationSnap: handleRotationSnap, handlePositionSnap: handlePositionSnap, calculateAlignments: calculateAlignments, calculateProximityLines: calculateProximityLines, detectProximityLines: detectProximityLines }));
|
|
297
|
+
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 banner-container-bg", postType === "STORY" ? "pb-32 pt-44" : "py-20"), onMouseMove: handleMouseMove, onClick: handleContainerClick, 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: {
|
|
298
|
+
opacity: Math.min(noiseIntensity / 2, 1), // Normalize 0-2 range to 0-1
|
|
299
|
+
mixBlendMode: 'overlay',
|
|
300
|
+
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")`,
|
|
301
|
+
zIndex: 5,
|
|
302
|
+
} })), (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: {
|
|
303
|
+
top: '50%',
|
|
304
|
+
left: '50%',
|
|
305
|
+
transform: `translate(${config.logo.x}px, ${config.logo.y * yMultiplier}px)`,
|
|
306
|
+
}, children: logoComponent }), creationMode && (completedLines.size > 0 || drawingFrom) && ((0, jsx_runtime_1.jsx)(components_1.InteractiveLines, { copies: copies, completedLines: completedLines, drawingFrom: drawingFrom, drawingMousePos: drawingMousePos, hoveredLine: hoveredLine, lineRecalcTrigger: lineRecalcTrigger, sizeMultiplier: sizeMultiplier, logoRef: logoRef, copyRefs: copyRefs, bannerContainerRef: bannerContainerRef, setCompletedLines: setCompletedLines, setManualLines: setManualLines, setHoveredLine: setHoveredLine })), (0, jsx_runtime_1.jsx)(components_1.VisualGuides, { draggableMode: draggableMode, isDragging: isDragging, selectedElement: selectedElement, alignmentLines: alignmentLines, proximityLines: proximityLines, liveDragPosition: liveDragPosition, logoTranslateX: logoTranslateX, logoTranslateY: logoTranslateY, copies: copies, config: config, autoOffsets: autoOffsets, yMultiplier: yMultiplier }), (0, jsx_runtime_1.jsx)("div", { className: "absolute pointer-events-none", style: {
|
|
307
|
+
top: '50%',
|
|
308
|
+
left: '50%',
|
|
309
|
+
width: 0,
|
|
310
|
+
height: 0,
|
|
311
|
+
zIndex: 10,
|
|
312
|
+
}, children: copies.map((copy, copyIndex) => {
|
|
313
|
+
var _a, _b;
|
|
314
|
+
// Get width from config for the wrapper
|
|
315
|
+
const styleSlot = copy.styleSlot !== undefined ? copy.styleSlot : copyIndex;
|
|
316
|
+
const copyConfig = ((_a = config.copies) === null || _a === void 0 ? void 0 : _a[styleSlot]) || ((_b = config.copies) === null || _b === void 0 ? void 0 : _b[0]);
|
|
317
|
+
const configWidth = copy.width || (copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.width);
|
|
318
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "pointer-events-auto absolute", style: {
|
|
319
|
+
top: '50%',
|
|
320
|
+
left: '50%',
|
|
321
|
+
width: configWidth,
|
|
322
|
+
}, children: (0, jsx_runtime_1.jsx)(components_1.CopyElement, { copy: copy, copyIndex: copyIndex, copies: copies, config: config, styleConfig: styleConfig, yMultiplier: yMultiplier, autoOffsets: autoOffsets, sizeMultiplier: sizeMultiplier, fontFamily: fontFamily, draggableMode: draggableMode, creationMode: creationMode, linkingModeActive: linkingModeActive, selectedElement: selectedElement, completedLines: completedLines, drawingFrom: drawingFrom, copyRefs: copyRefs, bannerContainerRef: bannerContainerRef, onCopyPositionChange: onCopyPositionChange, onCopyRotationChange: onCopyRotationChange, onCopyWidthChange: onCopyWidthChange, setSelectedElement: setSelectedElement, setIsDragging: setIsDragging, setLiveDragPosition: setLiveDragPosition, setAlignmentLines: setAlignmentLines, setProximityLines: setProximityLines, handleToggleAutoPositioning: handleToggleAutoPositioning, handleCompleteLineTo: handleCompleteLineTo, handleRotationSnap: handleRotationSnap, handlePositionSnap: handlePositionSnap, calculateAlignments: calculateAlignments, calculateProximityLines: calculateProximityLines, detectProximityLines: detectProximityLines }) }, copy.id));
|
|
323
|
+
}) })] }) }));
|
|
324
|
+
};
|
|
325
|
+
exports.BannerRenderer = BannerRenderer;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CopyElement component
|
|
3
|
+
* Renders a single copy/text element with drag, rotation, and resize capabilities
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { CopyConfig } from '../../../types';
|
|
7
|
+
import type { CopyElementConfig } from '../../styles/types/substyleTypes';
|
|
8
|
+
import type { AlignmentLine } from '../utils';
|
|
9
|
+
export interface CopyElementProps {
|
|
10
|
+
copy: CopyConfig;
|
|
11
|
+
copyIndex: number;
|
|
12
|
+
copies: CopyConfig[];
|
|
13
|
+
config: {
|
|
14
|
+
copies?: CopyElementConfig[];
|
|
15
|
+
};
|
|
16
|
+
styleConfig: {
|
|
17
|
+
copyFontWeights?: Record<number, string>;
|
|
18
|
+
fontFamily?: string;
|
|
19
|
+
};
|
|
20
|
+
yMultiplier: number;
|
|
21
|
+
autoOffsets: Record<number, number>;
|
|
22
|
+
sizeMultiplier: number;
|
|
23
|
+
fontFamily?: string;
|
|
24
|
+
draggableMode: boolean;
|
|
25
|
+
creationMode: boolean;
|
|
26
|
+
linkingModeActive: boolean;
|
|
27
|
+
selectedElement: string | null;
|
|
28
|
+
completedLines: Map<string, string>;
|
|
29
|
+
drawingFrom: string | null;
|
|
30
|
+
copyRefs: React.MutableRefObject<(HTMLDivElement | null)[]>;
|
|
31
|
+
bannerContainerRef: React.RefObject<HTMLDivElement | null>;
|
|
32
|
+
onCopyPositionChange?: (copyIndex: number, pos: {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
}) => void;
|
|
36
|
+
onCopyRotationChange?: (copyIndex: number, rotation: number) => void;
|
|
37
|
+
onCopyWidthChange?: (copyIndex: number, width: number) => void;
|
|
38
|
+
setSelectedElement: (id: string | null) => void;
|
|
39
|
+
setIsDragging: (dragging: boolean) => void;
|
|
40
|
+
setLiveDragPosition: (pos: {
|
|
41
|
+
elementId: string;
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
} | null) => void;
|
|
45
|
+
setAlignmentLines: (lines: AlignmentLine[]) => void;
|
|
46
|
+
setProximityLines: (lines: any[]) => void;
|
|
47
|
+
handleToggleAutoPositioning: (elementId: string) => void;
|
|
48
|
+
handleCompleteLineTo: (targetId: string) => void;
|
|
49
|
+
handleRotationSnap: (angle: number) => number;
|
|
50
|
+
handlePositionSnap: (bounds: DOMRect, position: {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
}) => {
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
};
|
|
57
|
+
calculateAlignments: (elementId: string) => AlignmentLine[];
|
|
58
|
+
calculateProximityLines: (elementId: string) => void;
|
|
59
|
+
detectProximityLines: (elementId: string) => void;
|
|
60
|
+
}
|
|
61
|
+
export declare const CopyElement: React.NamedExoticComponent<CopyElementProps>;
|
|
62
|
+
//# sourceMappingURL=CopyElement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopyElement.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/components/CopyElement.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CopyElement = void 0;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
/**
|
|
9
|
+
* CopyElement component
|
|
10
|
+
* Renders a single copy/text element with drag, rotation, and resize capabilities
|
|
11
|
+
*/
|
|
12
|
+
const react_1 = __importDefault(require("react"));
|
|
13
|
+
const clsx_1 = __importDefault(require("clsx"));
|
|
14
|
+
const shared_1 = require("../../shared");
|
|
15
|
+
const defaults_1 = require("../../../constants/defaults");
|
|
16
|
+
const utils_1 = require("../utils");
|
|
17
|
+
const CopyElementComponent = ({ copy, copyIndex, copies, config, styleConfig, yMultiplier, autoOffsets, sizeMultiplier, fontFamily, draggableMode, creationMode, linkingModeActive, selectedElement, completedLines, drawingFrom, copyRefs, bannerContainerRef, onCopyPositionChange, onCopyRotationChange, onCopyWidthChange, setSelectedElement, setIsDragging, setLiveDragPosition, setAlignmentLines, setProximityLines, handleToggleAutoPositioning, handleCompleteLineTo, handleRotationSnap, handlePositionSnap, calculateAlignments, calculateProximityLines, detectProximityLines, }) => {
|
|
18
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
19
|
+
// Use styleSlot to determine config (0 = first copy, 1 = second copy, etc.)
|
|
20
|
+
// Fallback to copyIndex for creation mode
|
|
21
|
+
const styleSlot = copy.styleSlot !== undefined ? copy.styleSlot : copyIndex;
|
|
22
|
+
// Wrapper to convert UUID-based targetId to styleSlot format before calling handleCompleteLineTo
|
|
23
|
+
// This is needed because DraggableElement passes elementId (UUID format) but completedLines uses styleSlot format
|
|
24
|
+
const handleCompleteLineToWithConversion = react_1.default.useCallback((targetId) => {
|
|
25
|
+
var _a;
|
|
26
|
+
// targetId comes as 'copy-{uuid}' from DraggableElement
|
|
27
|
+
// We need to find the copy with that UUID and get its styleSlot
|
|
28
|
+
if (targetId === 'logo') {
|
|
29
|
+
handleCompleteLineTo('logo');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (targetId.startsWith('copy-')) {
|
|
33
|
+
const suffix = targetId.substring(5); // Remove 'copy-' prefix
|
|
34
|
+
const targetCopy = copies.find(c => c.id === suffix);
|
|
35
|
+
const targetStyleSlot = (_a = targetCopy === null || targetCopy === void 0 ? void 0 : targetCopy.styleSlot) !== null && _a !== void 0 ? _a : copies.findIndex(c => c.id === suffix);
|
|
36
|
+
if (targetStyleSlot !== -1) {
|
|
37
|
+
handleCompleteLineTo(`copy-${targetStyleSlot}`);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// Fallback: pass as-is (handleCompleteLineTo will try to convert)
|
|
41
|
+
handleCompleteLineTo(targetId);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
handleCompleteLineTo(targetId);
|
|
46
|
+
}
|
|
47
|
+
}, [copies, handleCompleteLineTo]);
|
|
48
|
+
// DYNAMIC: Check if this styleSlot has config (not limited to 0 and 1)
|
|
49
|
+
const isStyled = ((_a = config.copies) === null || _a === void 0 ? void 0 : _a[styleSlot]) !== undefined;
|
|
50
|
+
// Get copy config from copies array
|
|
51
|
+
const copyConfig = ((_b = config.copies) === null || _b === void 0 ? void 0 : _b[styleSlot]) || ((_c = config.copies) === null || _c === void 0 ? void 0 : _c[0]);
|
|
52
|
+
// Get config position and width
|
|
53
|
+
const configX = (_d = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.x) !== null && _d !== void 0 ? _d : 0;
|
|
54
|
+
const configY = (_e = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.y) !== null && _e !== void 0 ? _e : 0;
|
|
55
|
+
const configWidth = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.width;
|
|
56
|
+
const autoOffset = autoOffsets[styleSlot] || 0;
|
|
57
|
+
// Get the font size multiplier from copy config (used for both font size and padding scaling)
|
|
58
|
+
const copyFontSizeMultiplier = copy.fontSize || 1.0;
|
|
59
|
+
// Calculate font size
|
|
60
|
+
// copy.fontSize is now an absolute multiplier, not relative to config
|
|
61
|
+
// Config fontSize values only set the initial copy.fontSize value
|
|
62
|
+
const effectiveFontSize = `${defaults_1.DEFAULT_BASE_FONT_SIZE_REM * copyFontSizeMultiplier}rem`;
|
|
63
|
+
// Get alignment - always prioritize copy's own align property
|
|
64
|
+
const effectiveAlign = copy.align || (isStyled && copyConfig ? copyConfig.alignment : 'center');
|
|
65
|
+
// Get font weight - use copy's fontWeight, then config default, then fallback
|
|
66
|
+
const effectiveFontWeight = copy.fontWeight || (isStyled ? (((_f = styleConfig.copyFontWeights) === null || _f === void 0 ? void 0 : _f[styleSlot]) || 'normal') : 'normal');
|
|
67
|
+
// Get font family - prioritize copy's own fontFamily, then global override, then style config
|
|
68
|
+
const effectiveCopyFontFamily = copy.fontFamily || fontFamily || styleConfig.fontFamily;
|
|
69
|
+
// Get color properties - prioritize copy's own properties, then substyle config, then defaults
|
|
70
|
+
const effectiveColor = copy.color || (isStyled && copyConfig ? copyConfig.color : undefined) || 'white';
|
|
71
|
+
const effectiveBgColor = copy.bgColor || (isStyled && copyConfig ? copyConfig.bgColor : undefined);
|
|
72
|
+
const effectiveHasBg = copy.hasBg !== undefined ? copy.hasBg : (isStyled && copyConfig ? copyConfig.hasBg : false);
|
|
73
|
+
// Get padding and scale it proportionally with font size to maintain visual consistency
|
|
74
|
+
const basePaddingX = copy.paddingX || (isStyled && copyConfig ? copyConfig.paddingX : undefined);
|
|
75
|
+
const basePaddingY = copy.paddingY || (isStyled && copyConfig ? copyConfig.paddingY : undefined);
|
|
76
|
+
const effectivePaddingX = basePaddingX
|
|
77
|
+
? `${parseFloat(basePaddingX.replace('rem', '')) * copyFontSizeMultiplier}rem`
|
|
78
|
+
: undefined;
|
|
79
|
+
const effectivePaddingY = basePaddingY
|
|
80
|
+
? `${parseFloat(basePaddingY.replace('rem', '')) * copyFontSizeMultiplier}rem`
|
|
81
|
+
: undefined;
|
|
82
|
+
const effectiveBorderRadius = copy.borderRadius || (isStyled && copyConfig ? copyConfig.borderRadius : undefined);
|
|
83
|
+
// Apply text decoration styles
|
|
84
|
+
const textDecorationStyles = [];
|
|
85
|
+
if (copy.underline)
|
|
86
|
+
textDecorationStyles.push('underline');
|
|
87
|
+
const textDecoration = textDecorationStyles.length > 0 ? textDecorationStyles.join(' ') : 'none';
|
|
88
|
+
// Apply font style
|
|
89
|
+
const fontStyle = copy.italic ? 'italic' : 'normal';
|
|
90
|
+
// Apply additional bold if textBold is true (combines with fontWeight)
|
|
91
|
+
const finalFontWeight = copy.textBold
|
|
92
|
+
? 'bold'
|
|
93
|
+
: (0, utils_1.getFontWeight)(effectiveFontWeight);
|
|
94
|
+
// Text element
|
|
95
|
+
const textElement = ((0, jsx_runtime_1.jsx)("p", { style: {
|
|
96
|
+
fontSize: effectiveFontSize,
|
|
97
|
+
fontWeight: finalFontWeight,
|
|
98
|
+
fontFamily: effectiveCopyFontFamily,
|
|
99
|
+
color: effectiveColor,
|
|
100
|
+
textDecoration,
|
|
101
|
+
fontStyle,
|
|
102
|
+
}, className: (0, clsx_1.default)("whitespace-pre-wrap", `text-${effectiveAlign}`), children: copy.text }));
|
|
103
|
+
// Wrap with background if needed
|
|
104
|
+
const contentElement = effectiveHasBg ? ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
105
|
+
backgroundColor: effectiveBgColor,
|
|
106
|
+
paddingLeft: effectivePaddingX,
|
|
107
|
+
paddingRight: effectivePaddingX,
|
|
108
|
+
paddingTop: effectivePaddingY,
|
|
109
|
+
paddingBottom: effectivePaddingY,
|
|
110
|
+
borderRadius: effectiveBorderRadius,
|
|
111
|
+
display: 'inline-block',
|
|
112
|
+
}, children: textElement })) : textElement;
|
|
113
|
+
// Calculate final position: config position + auto-offset + user adjustment
|
|
114
|
+
const baseX = isStyled ? configX : 0;
|
|
115
|
+
const baseY = isStyled ? (configY * yMultiplier + autoOffset) : 0;
|
|
116
|
+
// DYNAMIC: Consistent 'copy-N' format for all styleSlots
|
|
117
|
+
const elementId = `copy-${styleSlot}`;
|
|
118
|
+
// Plan v30: Check if this element is a TARGET in the chain
|
|
119
|
+
// TARGETs appear as values in completedLines (they are the "to" in "from -> to")
|
|
120
|
+
// When an element is a TARGET with autoOffset, ignore translateY because position is calculated by auto-positioning
|
|
121
|
+
const isTargetInChain = react_1.default.useMemo(() => {
|
|
122
|
+
// Check if this element appears as a target (value) in completedLines
|
|
123
|
+
for (const [, toId] of completedLines.entries()) {
|
|
124
|
+
if (toId === `copy-${styleSlot}`) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}, [completedLines, styleSlot]);
|
|
130
|
+
// If element is TARGET in chain and has autoOffset, ignore translateY
|
|
131
|
+
// This ensures auto-positioning controls the Y position completely
|
|
132
|
+
const effectiveTranslateY = (isTargetInChain && autoOffset !== 0) ? 0 : (copy.translateY || 0);
|
|
133
|
+
const finalX = baseX + (copy.translateX || 0);
|
|
134
|
+
const finalY = baseY + effectiveTranslateY;
|
|
135
|
+
const finalWidth = copy.width || configWidth;
|
|
136
|
+
const finalRotation = (_g = copy.rotation) !== null && _g !== void 0 ? _g : (isStyled ? ((_h = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.rotation) !== null && _h !== void 0 ? _h : 0) : 0);
|
|
137
|
+
// DEBUG: Log positioning only when final position changes (not on every render)
|
|
138
|
+
react_1.default.useEffect(() => {
|
|
139
|
+
console.log(`📍 Copy[${styleSlot}] position changed:`, {
|
|
140
|
+
finalX: Math.round(finalX),
|
|
141
|
+
finalY: Math.round(finalY),
|
|
142
|
+
baseY: Math.round(baseY),
|
|
143
|
+
autoOffset: Math.round(autoOffset),
|
|
144
|
+
translateY: Math.round(effectiveTranslateY),
|
|
145
|
+
});
|
|
146
|
+
}, [finalX, finalY, styleSlot, baseY, autoOffset, effectiveTranslateY]);
|
|
147
|
+
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, creationMode: creationMode, linkingModeActive: linkingModeActive, onStartLinking: creationMode && linkingModeActive ? () => handleToggleAutoPositioning(`copy-${styleSlot}`) : undefined, onElementClickWhileDrawing: creationMode && drawingFrom ? handleCompleteLineToWithConversion : undefined, onPositionChange: (pos) => {
|
|
148
|
+
// Clear live drag position and dragging state when drag ends
|
|
149
|
+
setLiveDragPosition(null);
|
|
150
|
+
setIsDragging(false);
|
|
151
|
+
setAlignmentLines([]); // Clear alignment lines
|
|
152
|
+
setProximityLines([]); // Clear proximity lines
|
|
153
|
+
// Subtract base position to get only user adjustment
|
|
154
|
+
const adjustedPos = {
|
|
155
|
+
x: pos.x - baseX,
|
|
156
|
+
y: pos.y - baseY,
|
|
157
|
+
};
|
|
158
|
+
// Find index of this copy in the copies array to call the callback
|
|
159
|
+
const foundIndex = copies.findIndex(c => c.id === copy.id);
|
|
160
|
+
if (foundIndex !== -1) {
|
|
161
|
+
console.log('🖱️ COPY DRAG - copyIndex:', foundIndex, 'adjustedPos:', adjustedPos);
|
|
162
|
+
onCopyPositionChange === null || onCopyPositionChange === void 0 ? void 0 : onCopyPositionChange(foundIndex, adjustedPos);
|
|
163
|
+
}
|
|
164
|
+
}, onRotationChange: (rot) => {
|
|
165
|
+
const foundIndex = copies.findIndex(c => c.id === copy.id);
|
|
166
|
+
if (foundIndex !== -1) {
|
|
167
|
+
onCopyRotationChange === null || onCopyRotationChange === void 0 ? void 0 : onCopyRotationChange(foundIndex, rot);
|
|
168
|
+
}
|
|
169
|
+
}, onWidthChange: (w) => {
|
|
170
|
+
const foundIndex = copies.findIndex(c => c.id === copy.id);
|
|
171
|
+
if (foundIndex !== -1) {
|
|
172
|
+
onCopyWidthChange === null || onCopyWidthChange === void 0 ? void 0 : onCopyWidthChange(foundIndex, w);
|
|
173
|
+
}
|
|
174
|
+
}, onSelect: (id) => setSelectedElement(id), onDeselect: () => {
|
|
175
|
+
setSelectedElement(null);
|
|
176
|
+
setLiveDragPosition(null);
|
|
177
|
+
setProximityLines([]); // Clear proximity lines
|
|
178
|
+
}, onRotationSnap: handleRotationSnap, onPositionSnap: handlePositionSnap, onDragMove: (dragElementId, bounds) => {
|
|
179
|
+
// Set dragging state to true
|
|
180
|
+
setIsDragging(true);
|
|
181
|
+
// Calculate live position from element bounds
|
|
182
|
+
if (!bannerContainerRef.current)
|
|
183
|
+
return;
|
|
184
|
+
const bannerBounds = bannerContainerRef.current.getBoundingClientRect();
|
|
185
|
+
const elementCenterX = bounds.left + bounds.width / 2;
|
|
186
|
+
const elementCenterY = bounds.top + bounds.height / 2;
|
|
187
|
+
// Banner center in viewport coordinates
|
|
188
|
+
const bannerCenterX = bannerBounds.left + bannerBounds.width / 2;
|
|
189
|
+
const bannerCenterY = bannerBounds.top + bannerBounds.height / 2;
|
|
190
|
+
// Calculate offset from banner center (in scaled pixels)
|
|
191
|
+
const offsetX = (elementCenterX - bannerCenterX) / sizeMultiplier;
|
|
192
|
+
const offsetY = (elementCenterY - bannerCenterY) / sizeMultiplier;
|
|
193
|
+
// Store the live position
|
|
194
|
+
setLiveDragPosition({
|
|
195
|
+
elementId: dragElementId,
|
|
196
|
+
x: offsetX,
|
|
197
|
+
y: offsetY,
|
|
198
|
+
});
|
|
199
|
+
// Calculate alignment lines
|
|
200
|
+
const alignments = calculateAlignments(dragElementId);
|
|
201
|
+
setAlignmentLines(alignments);
|
|
202
|
+
// Calculate proximity lines (visual distance indicators)
|
|
203
|
+
calculateProximityLines(dragElementId);
|
|
204
|
+
// Detect proximity and auto-create lines (creation mode only)
|
|
205
|
+
detectProximityLines(dragElementId);
|
|
206
|
+
}, children: (0, jsx_runtime_1.jsx)("div", { ref: (el) => {
|
|
207
|
+
// Store ref by copy index in the copies array
|
|
208
|
+
const foundIndex = copies.findIndex(c => c.id === copy.id);
|
|
209
|
+
if (foundIndex !== -1) {
|
|
210
|
+
copyRefs.current[foundIndex] = el;
|
|
211
|
+
}
|
|
212
|
+
}, style: {
|
|
213
|
+
// Remove transform - DraggableElement already handles positioning and rotation
|
|
214
|
+
width: '100%',
|
|
215
|
+
// Hide copy if hidden property is true
|
|
216
|
+
display: copy.hidden ? 'none' : undefined,
|
|
217
|
+
}, children: contentElement }) }, copy.id));
|
|
218
|
+
};
|
|
219
|
+
// Memoize CopyElement to prevent unnecessary re-renders
|
|
220
|
+
exports.CopyElement = react_1.default.memo(CopyElementComponent);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InteractiveLines component
|
|
3
|
+
* Renders the green dotted lines for auto-positioning connections between elements
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { CopyConfig } from '../../../types';
|
|
7
|
+
export interface InteractiveLinesProps {
|
|
8
|
+
copies: CopyConfig[];
|
|
9
|
+
completedLines: Map<string, string>;
|
|
10
|
+
drawingFrom: string | null;
|
|
11
|
+
drawingMousePos: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
} | null;
|
|
15
|
+
hoveredLine: string | null;
|
|
16
|
+
lineRecalcTrigger: number;
|
|
17
|
+
sizeMultiplier: number;
|
|
18
|
+
logoRef: React.RefObject<HTMLDivElement | null>;
|
|
19
|
+
copyRefs: React.MutableRefObject<(HTMLDivElement | null)[]>;
|
|
20
|
+
bannerContainerRef: React.RefObject<HTMLDivElement | null>;
|
|
21
|
+
setCompletedLines: React.Dispatch<React.SetStateAction<Map<string, string>>>;
|
|
22
|
+
setManualLines: React.Dispatch<React.SetStateAction<Set<string>>>;
|
|
23
|
+
setHoveredLine: (lineId: string | null) => void;
|
|
24
|
+
}
|
|
25
|
+
export declare const InteractiveLines: React.FC<InteractiveLinesProps>;
|
|
26
|
+
//# sourceMappingURL=InteractiveLines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InteractiveLines.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/components/InteractiveLines.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,WAAW,qBAAqB;IAEpC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IAGvB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAChD,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,kBAAkB,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAG3D,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7E,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA4Q5D,CAAC"}
|