zuljaman-banner-components 1.0.23 → 1.0.25
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 +73 -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 +335 -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,491 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useProximityDetection hook
|
|
4
|
+
* Handles auto-detection of proximity chains and visual proximity indicators
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.useProximityDetection = useProximityDetection;
|
|
41
|
+
const react_1 = __importStar(require("react"));
|
|
42
|
+
const constants_1 = require("../constants");
|
|
43
|
+
const utils_1 = require("../utils");
|
|
44
|
+
/**
|
|
45
|
+
* Hook that handles auto-detection of proximity chains and visual proximity line indicators.
|
|
46
|
+
*/
|
|
47
|
+
function useProximityDetection({ logoRef, copyRefs, bannerContainerRef, copies, sizeMultiplier, creationMode, manualLines, completedLines, setCompletedLines, setLineGaps, getElementRef, }) {
|
|
48
|
+
// Proximity lines state (visual distance indicators)
|
|
49
|
+
const [proximityLines, setProximityLines] = (0, react_1.useState)([]);
|
|
50
|
+
// Auto-detect proximity and create lines
|
|
51
|
+
const detectProximityLines = react_1.default.useCallback((draggedElementId) => {
|
|
52
|
+
// DEBUG: Log entry point
|
|
53
|
+
// console.log('🔍 detectProximityLines called', { draggedElementId, creationMode, hasBannerRef: !!bannerContainerRef.current });
|
|
54
|
+
if (!creationMode || !bannerContainerRef.current) {
|
|
55
|
+
// console.log('🔍 detectProximityLines SKIPPED - creationMode:', creationMode, 'hasBannerRef:', !!bannerContainerRef.current);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const proximityThreshold = constants_1.PROXIMITY_THRESHOLD_PX;
|
|
59
|
+
// Get all elements - PHASE 1: Use styleSlot format for IDs (copy-N)
|
|
60
|
+
const allElements = [
|
|
61
|
+
{ id: 'logo', ref: logoRef.current },
|
|
62
|
+
...copies.map((copy, index) => ({
|
|
63
|
+
// Use styleSlot if available, otherwise fall back to array index
|
|
64
|
+
id: `copy-${copy.styleSlot !== undefined ? copy.styleSlot : index}`,
|
|
65
|
+
ref: copyRefs.current[index],
|
|
66
|
+
})),
|
|
67
|
+
];
|
|
68
|
+
// Convert draggedElementId from copy-{uuid} to copy-{styleSlot} format
|
|
69
|
+
let draggedStyleSlotId = draggedElementId;
|
|
70
|
+
if (draggedElementId.startsWith('copy-')) {
|
|
71
|
+
const suffix = draggedElementId.substring(5);
|
|
72
|
+
// If it's NOT a number, it's a UUID - convert to styleSlot format
|
|
73
|
+
if (!/^\d+$/.test(suffix)) {
|
|
74
|
+
const draggedCopy = copies.find(c => c.id === suffix);
|
|
75
|
+
if (draggedCopy) {
|
|
76
|
+
const styleSlot = draggedCopy.styleSlot !== undefined ? draggedCopy.styleSlot : copies.indexOf(draggedCopy);
|
|
77
|
+
draggedStyleSlotId = `copy-${styleSlot}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// console.log('🔍 Converted draggedElementId:', { original: draggedElementId, converted: draggedStyleSlotId });
|
|
82
|
+
// Step 1: Collect element bounds
|
|
83
|
+
const elementBounds = new Map();
|
|
84
|
+
allElements.forEach(({ id, ref }) => {
|
|
85
|
+
if (ref) {
|
|
86
|
+
elementBounds.set(id, ref.getBoundingClientRect());
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// Step 2: Build proximity graph using utility function
|
|
90
|
+
const adjacencyGraph = (0, utils_1.buildProximityGraph)(elementBounds, proximityThreshold, sizeMultiplier);
|
|
91
|
+
// Step 3: Find connected clusters using Union-Find
|
|
92
|
+
const clusters = (0, utils_1.findConnectedClusters)(adjacencyGraph);
|
|
93
|
+
// Step 4: Create proximity map with intelligent chain extension
|
|
94
|
+
// When extending existing chains, the chain tail becomes SOURCE, new element becomes TARGET
|
|
95
|
+
const proximityMap = new Map();
|
|
96
|
+
// Helper: Get the tail of an existing chain (TARGET that is NOT a SOURCE)
|
|
97
|
+
const getChainTail = (completedLines) => {
|
|
98
|
+
if (completedLines.size === 0)
|
|
99
|
+
return null;
|
|
100
|
+
const targets = new Set(completedLines.values());
|
|
101
|
+
const sources = new Set(completedLines.keys());
|
|
102
|
+
for (const target of targets) {
|
|
103
|
+
if (!sources.has(target)) {
|
|
104
|
+
return target; // TARGET that is NOT a SOURCE = chain tail
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
109
|
+
// Helper: Check if element is already part of the chain
|
|
110
|
+
const isInChain = (elementId, completedLines) => {
|
|
111
|
+
return completedLines.has(elementId) ||
|
|
112
|
+
Array.from(completedLines.values()).includes(elementId);
|
|
113
|
+
};
|
|
114
|
+
// clusters is Map<string, string[]> where key is root ID and value is array of element IDs
|
|
115
|
+
clusters.forEach((clusterElements) => {
|
|
116
|
+
var _a;
|
|
117
|
+
if (clusterElements.length < 2)
|
|
118
|
+
return;
|
|
119
|
+
const draggedIsInCluster = clusterElements.includes(draggedStyleSlotId);
|
|
120
|
+
if (draggedIsInCluster && clusterElements.length === 2) {
|
|
121
|
+
// For 2-element clusters with dragged element:
|
|
122
|
+
const otherElement = clusterElements.find(e => e !== draggedStyleSlotId);
|
|
123
|
+
if (otherElement) {
|
|
124
|
+
// Use completedLines directly to determine link direction
|
|
125
|
+
const chainTail = getChainTail(completedLines);
|
|
126
|
+
const otherIsChainTail = otherElement === chainTail;
|
|
127
|
+
const draggedIsChainTail = draggedStyleSlotId === chainTail;
|
|
128
|
+
const draggedInChain = isInChain(draggedStyleSlotId, completedLines);
|
|
129
|
+
const otherInChain = isInChain(otherElement, completedLines);
|
|
130
|
+
// console.log('🔗 Chain analysis for link creation:', {
|
|
131
|
+
// chainTail,
|
|
132
|
+
// otherElement,
|
|
133
|
+
// draggedStyleSlotId,
|
|
134
|
+
// otherIsChainTail,
|
|
135
|
+
// draggedIsChainTail,
|
|
136
|
+
// draggedInChain,
|
|
137
|
+
// otherInChain,
|
|
138
|
+
// existingChain: Array.from(completedLines.entries()),
|
|
139
|
+
// });
|
|
140
|
+
let sourceId;
|
|
141
|
+
let targetId;
|
|
142
|
+
if (otherIsChainTail && !draggedInChain) {
|
|
143
|
+
// Other element is chain tail, dragged is new - extend chain
|
|
144
|
+
sourceId = otherElement;
|
|
145
|
+
targetId = draggedStyleSlotId;
|
|
146
|
+
// console.log('🔗 Extending chain: tail becomes source', `${sourceId} → ${targetId}`);
|
|
147
|
+
}
|
|
148
|
+
else if (draggedIsChainTail && !otherInChain) {
|
|
149
|
+
// Dragged is chain tail, other is new - extend chain
|
|
150
|
+
sourceId = draggedStyleSlotId;
|
|
151
|
+
targetId = otherElement;
|
|
152
|
+
// console.log('🔗 Extending chain: dragged tail becomes source', `${sourceId} → ${targetId}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Default: static element = ANCHOR, dragged = TARGET
|
|
156
|
+
sourceId = otherElement;
|
|
157
|
+
targetId = draggedStyleSlotId;
|
|
158
|
+
// console.log('🔗 Default link creation (dragged as TARGET):', `${sourceId} → ${targetId}`);
|
|
159
|
+
}
|
|
160
|
+
proximityMap.set(sourceId, targetId);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// Clusters of 3+ elements or dragged not in cluster
|
|
165
|
+
// IMPORTANT: Respect existing chains and only extend them
|
|
166
|
+
// 1. Find which elements are already in the chain
|
|
167
|
+
const elementsInChain = clusterElements.filter(e => isInChain(e, completedLines));
|
|
168
|
+
const elementsNotInChain = clusterElements.filter(e => !isInChain(e, completedLines));
|
|
169
|
+
// console.log('🔗 Large cluster analysis:', {
|
|
170
|
+
// clusterSize: clusterElements.length,
|
|
171
|
+
// elementsInChain,
|
|
172
|
+
// elementsNotInChain,
|
|
173
|
+
// chainTail: getChainTail(completedLines),
|
|
174
|
+
// draggedStyleSlotId,
|
|
175
|
+
// });
|
|
176
|
+
// 2. If there are new elements (not in chain) and a chain exists
|
|
177
|
+
if (elementsNotInChain.length > 0 && completedLines.size > 0) {
|
|
178
|
+
const chainTail = getChainTail(completedLines);
|
|
179
|
+
if (chainTail && clusterElements.includes(chainTail)) {
|
|
180
|
+
// The chain tail is in this cluster
|
|
181
|
+
// CRITICAL: chainTail is the element that is TARGET but NOT SOURCE
|
|
182
|
+
// It's already the tail, so it CAN be a source for the next element
|
|
183
|
+
// Only extend if the dragged element is new (not already in chain)
|
|
184
|
+
if (elementsNotInChain.includes(draggedStyleSlotId)) {
|
|
185
|
+
proximityMap.set(chainTail, draggedStyleSlotId);
|
|
186
|
+
// console.log('🔗 Extending chain from tail:', `${chainTail} → ${draggedStyleSlotId}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else if (completedLines.size === 0) {
|
|
191
|
+
// No existing chain - detect edge and order accordingly
|
|
192
|
+
const bannerBounds = (_a = bannerContainerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
193
|
+
if (bannerBounds) {
|
|
194
|
+
// Calculate cluster's center Y to determine which edge it's closer to
|
|
195
|
+
let clusterCenterY = 0;
|
|
196
|
+
let validElements = 0;
|
|
197
|
+
clusterElements.forEach(e => {
|
|
198
|
+
const bounds = elementBounds.get(e);
|
|
199
|
+
if (bounds) {
|
|
200
|
+
clusterCenterY += bounds.top + bounds.height / 2;
|
|
201
|
+
validElements++;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
clusterCenterY = validElements > 0 ? clusterCenterY / validElements : 0;
|
|
205
|
+
const bannerCenterY = bannerBounds.top + bannerBounds.height / 2;
|
|
206
|
+
const isCloserToBottom = clusterCenterY > bannerCenterY;
|
|
207
|
+
// Sort elements by Y position
|
|
208
|
+
const sorted = [...clusterElements].sort((a, b) => {
|
|
209
|
+
const boundsA = elementBounds.get(a);
|
|
210
|
+
const boundsB = elementBounds.get(b);
|
|
211
|
+
if (!boundsA || !boundsB)
|
|
212
|
+
return 0;
|
|
213
|
+
const centerA = boundsA.top + boundsA.height / 2;
|
|
214
|
+
const centerB = boundsB.top + boundsB.height / 2;
|
|
215
|
+
// If closer to bottom: sort descending (highest Y = ANCHOR first)
|
|
216
|
+
// If closer to top: sort ascending (lowest Y = ANCHOR first)
|
|
217
|
+
return isCloserToBottom
|
|
218
|
+
? centerB - centerA // bottom anchor: highest Y first
|
|
219
|
+
: centerA - centerB; // top anchor: lowest Y first
|
|
220
|
+
});
|
|
221
|
+
// Create chain: ANCHOR → TARGET1 → TARGET2 → ...
|
|
222
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
223
|
+
proximityMap.set(sorted[i], sorted[i + 1]);
|
|
224
|
+
}
|
|
225
|
+
// console.log('🔗 Y-ordering for new chain:', {
|
|
226
|
+
// isCloserToBottom,
|
|
227
|
+
// sorted,
|
|
228
|
+
// chain: sorted.slice(0, -1).map((s, i) => `${s} → ${sorted[i + 1]}`).join(', ')
|
|
229
|
+
// });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// If all elements are already in chain, don't create new links
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
// DEBUG: Log proximity detection results
|
|
236
|
+
// console.log('🔍 Proximity detection results:', {
|
|
237
|
+
// elementCount: elementBounds.size,
|
|
238
|
+
// clusterCount: clusters.size,
|
|
239
|
+
// proximityMapSize: proximityMap.size,
|
|
240
|
+
// proximityMapEntries: Array.from(proximityMap.entries()),
|
|
241
|
+
// draggedStyleSlotId,
|
|
242
|
+
// });
|
|
243
|
+
// Update lines based on proximity
|
|
244
|
+
setCompletedLines(prev => {
|
|
245
|
+
const newMap = new Map(prev);
|
|
246
|
+
// CRITICAL FIX: If proximityMap is empty (no drag active), keep all existing links
|
|
247
|
+
// Links should only be removed when there's actual proximity detection happening
|
|
248
|
+
if (proximityMap.size === 0) {
|
|
249
|
+
return prev; // Keep all existing links unchanged
|
|
250
|
+
}
|
|
251
|
+
// First, remove auto-proximity lines that are no longer valid
|
|
252
|
+
// Only remove if: (1) NOT a manual line AND (2) elements are no longer in proximity
|
|
253
|
+
let deletedLinks = [];
|
|
254
|
+
prev.forEach((targetId, sourceId) => {
|
|
255
|
+
const isManualLine = manualLines.has(`${sourceId}->${targetId}`);
|
|
256
|
+
// CRITICAL: Check if proximityMap wants to INVERT this link
|
|
257
|
+
// If so, DON'T remove it - keep the original direction
|
|
258
|
+
const inverseInProximityMap = proximityMap.get(targetId) === sourceId;
|
|
259
|
+
// CRITICAL FIX: Never delete links from completedLines unless proximityMap explicitly replaces them
|
|
260
|
+
// A link should ONLY be deleted if:
|
|
261
|
+
// 1. Source exists in proximityMap but points to a DIFFERENT target (being replaced)
|
|
262
|
+
// 2. AND it's not a manual line
|
|
263
|
+
// 3. AND proximityMap is not inverting it
|
|
264
|
+
const sourceHasNewTarget = proximityMap.has(sourceId) &&
|
|
265
|
+
proximityMap.get(sourceId) !== targetId;
|
|
266
|
+
// Only delete if source is being actively replaced with a different target
|
|
267
|
+
if (!isManualLine && !inverseInProximityMap && sourceHasNewTarget) {
|
|
268
|
+
deletedLinks.push(`${sourceId}→${targetId}`);
|
|
269
|
+
newMap.delete(sourceId);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
// Only log if links were deleted
|
|
273
|
+
// if (deletedLinks.length > 0) {
|
|
274
|
+
// console.log('🗑️ [THIRD ELEMENT] DELETED links', {
|
|
275
|
+
// deleted: deletedLinks,
|
|
276
|
+
// prevLinks: Array.from(prev.entries()).map(([s,t]) => `${s}→${t}`),
|
|
277
|
+
// remainingLinks: Array.from(newMap.entries()).map(([s,t]) => `${s}→${t}`),
|
|
278
|
+
// proximityLinks: Array.from(proximityMap.entries()).map(([s,t]) => `${s}→${t}`),
|
|
279
|
+
// });
|
|
280
|
+
// }
|
|
281
|
+
// Then, add auto-proximity lines
|
|
282
|
+
const newLinksToAdd = [];
|
|
283
|
+
proximityMap.forEach((targetId, sourceId) => {
|
|
284
|
+
const currentTarget = prev.get(sourceId);
|
|
285
|
+
const isManualLine = currentTarget && manualLines.has(`${sourceId}->${currentTarget}`);
|
|
286
|
+
// Don't override manual lines
|
|
287
|
+
if (isManualLine) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
// CRITICAL: Check if there's ALREADY a link in the OPPOSITE direction in newMap
|
|
291
|
+
// This prevents direction inversion when one element moves above/below another
|
|
292
|
+
if (newMap.get(targetId) === sourceId) {
|
|
293
|
+
// Link already exists in opposite direction - keep it, don't add inverted
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
// CRITICAL: Check if this source already has a target (preserve existing links)
|
|
297
|
+
if (newMap.has(sourceId)) {
|
|
298
|
+
// Source already connected to something - don't change it
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
// Add new link
|
|
302
|
+
newMap.set(sourceId, targetId);
|
|
303
|
+
newLinksToAdd.push({ sourceId, targetId });
|
|
304
|
+
});
|
|
305
|
+
// Only log if new links were added
|
|
306
|
+
// if (newLinksToAdd.length > 0) {
|
|
307
|
+
// console.log('➕ [THIRD ELEMENT] ADDED new links', {
|
|
308
|
+
// added: newLinksToAdd.map(({sourceId, targetId}) => `${sourceId}→${targetId}`),
|
|
309
|
+
// finalLinks: Array.from(newMap.entries()).map(([s,t]) => `${s}→${t}`)
|
|
310
|
+
// });
|
|
311
|
+
// }
|
|
312
|
+
// Calculate and store gap for new links
|
|
313
|
+
if (newLinksToAdd.length > 0) {
|
|
314
|
+
setLineGaps(prevGaps => {
|
|
315
|
+
const newGaps = new Map(prevGaps);
|
|
316
|
+
newLinksToAdd.forEach(({ sourceId, targetId }) => {
|
|
317
|
+
const lineKey = `${sourceId}->${targetId}`;
|
|
318
|
+
// Only calculate gap if it doesn't already exist
|
|
319
|
+
if (!newGaps.has(lineKey)) {
|
|
320
|
+
const anchorBounds = elementBounds.get(sourceId);
|
|
321
|
+
const targetBounds = elementBounds.get(targetId);
|
|
322
|
+
if (anchorBounds && targetBounds) {
|
|
323
|
+
// Calculate gap based on center-to-center distance minus half heights
|
|
324
|
+
// This gives the actual edge-to-edge gap regardless of overlap
|
|
325
|
+
const anchorCenterY = anchorBounds.top + anchorBounds.height / 2;
|
|
326
|
+
const targetCenterY = targetBounds.top + targetBounds.height / 2;
|
|
327
|
+
const anchorHalfHeight = anchorBounds.height / 2;
|
|
328
|
+
const targetHalfHeight = targetBounds.height / 2;
|
|
329
|
+
// Distance between centers minus the sum of half-heights = edge gap
|
|
330
|
+
const centerDistance = Math.abs(targetCenterY - anchorCenterY);
|
|
331
|
+
const rawGapPixels = (centerDistance - anchorHalfHeight - targetHalfHeight) / sizeMultiplier;
|
|
332
|
+
// If gap is negative (overlapping) or very small, use minimum gap
|
|
333
|
+
const MIN_GAP_PIXELS = 8; // 0.5rem minimum
|
|
334
|
+
const effectiveGapPixels = Math.max(rawGapPixels, MIN_GAP_PIXELS);
|
|
335
|
+
const gapRem = effectiveGapPixels / 16; // Convert to rem
|
|
336
|
+
newGaps.set(lineKey, gapRem);
|
|
337
|
+
console.log(`📏 Stored gap for ${lineKey}: ${gapRem.toFixed(2)}rem (raw: ${rawGapPixels.toFixed(0)}px, effective: ${effectiveGapPixels.toFixed(0)}px)`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
return newGaps;
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
// CRITICAL FIX: Always return new Map to ensure useEffect triggers
|
|
345
|
+
// This is necessary for the reset/preserve logic to run when new lines are added
|
|
346
|
+
return newMap;
|
|
347
|
+
});
|
|
348
|
+
}, [logoRef, copyRefs, bannerContainerRef, copies, manualLines, completedLines, creationMode, sizeMultiplier, setCompletedLines, setLineGaps]);
|
|
349
|
+
// Calculate proximity lines (visual distance indicators)
|
|
350
|
+
const calculateProximityLines = react_1.default.useCallback((draggedElementId) => {
|
|
351
|
+
if (!bannerContainerRef.current)
|
|
352
|
+
return;
|
|
353
|
+
const proximityThreshold = constants_1.PROXIMITY_THRESHOLD_PX;
|
|
354
|
+
// Helper to get element ref (PHASE 1: supports both copy-{uuid} and copy-{N} formats)
|
|
355
|
+
const getElementRefLocal = (elementId) => {
|
|
356
|
+
if (elementId === 'logo') {
|
|
357
|
+
return logoRef.current;
|
|
358
|
+
}
|
|
359
|
+
else if (elementId.startsWith('copy-')) {
|
|
360
|
+
const suffix = elementId.substring(5); // Remove 'copy-' prefix
|
|
361
|
+
// Check if it's copy-N format (styleSlot)
|
|
362
|
+
if (/^\d+$/.test(suffix)) {
|
|
363
|
+
const styleSlotIndex = parseInt(suffix, 10);
|
|
364
|
+
// Find copy by styleSlot first, then fallback to array index
|
|
365
|
+
const copy = copies.find(c => c.styleSlot === styleSlotIndex);
|
|
366
|
+
if (copy) {
|
|
367
|
+
const copyIndex = copies.indexOf(copy);
|
|
368
|
+
return copyRefs.current[copyIndex];
|
|
369
|
+
}
|
|
370
|
+
// Fallback to array index
|
|
371
|
+
if (styleSlotIndex < copies.length) {
|
|
372
|
+
return copyRefs.current[styleSlotIndex];
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
// It's a UUID format - find by id
|
|
377
|
+
const copyIndex = copies.findIndex(c => c.id === suffix);
|
|
378
|
+
if (copyIndex !== -1) {
|
|
379
|
+
return copyRefs.current[copyIndex];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return null;
|
|
384
|
+
};
|
|
385
|
+
// Helper to get element center position
|
|
386
|
+
const getElementCenter = (elementId) => {
|
|
387
|
+
const ref = getElementRefLocal(elementId);
|
|
388
|
+
if (!ref || !bannerContainerRef.current)
|
|
389
|
+
return null;
|
|
390
|
+
const elementBounds = ref.getBoundingClientRect();
|
|
391
|
+
const bannerBounds = bannerContainerRef.current.getBoundingClientRect();
|
|
392
|
+
const centerX = elementBounds.left + elementBounds.width / 2;
|
|
393
|
+
const centerY = elementBounds.top + elementBounds.height / 2;
|
|
394
|
+
const bannerCenterX = bannerBounds.left + bannerBounds.width / 2;
|
|
395
|
+
const bannerCenterY = bannerBounds.top + bannerBounds.height / 2;
|
|
396
|
+
return {
|
|
397
|
+
x: (centerX - bannerCenterX) / sizeMultiplier,
|
|
398
|
+
y: (centerY - bannerCenterY) / sizeMultiplier,
|
|
399
|
+
};
|
|
400
|
+
};
|
|
401
|
+
// Helper to get border intersection point
|
|
402
|
+
const getBorderPoint = (elementId, fromX, fromY) => {
|
|
403
|
+
const ref = getElementRef(elementId);
|
|
404
|
+
if (!ref || !bannerContainerRef.current)
|
|
405
|
+
return null;
|
|
406
|
+
const elementBounds = ref.getBoundingClientRect();
|
|
407
|
+
const bannerBounds = bannerContainerRef.current.getBoundingClientRect();
|
|
408
|
+
const width = elementBounds.width / sizeMultiplier;
|
|
409
|
+
const height = elementBounds.height / sizeMultiplier;
|
|
410
|
+
const centerXAbs = elementBounds.left + elementBounds.width / 2;
|
|
411
|
+
const centerYAbs = elementBounds.top + elementBounds.height / 2;
|
|
412
|
+
const bannerCenterX = bannerBounds.left + bannerBounds.width / 2;
|
|
413
|
+
const bannerCenterY = bannerBounds.top + bannerBounds.height / 2;
|
|
414
|
+
const centerX = (centerXAbs - bannerCenterX) / sizeMultiplier;
|
|
415
|
+
const centerY = (centerYAbs - bannerCenterY) / sizeMultiplier;
|
|
416
|
+
const dx = centerX - fromX;
|
|
417
|
+
const dy = centerY - fromY;
|
|
418
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
419
|
+
if (distance === 0)
|
|
420
|
+
return { x: centerX, y: centerY };
|
|
421
|
+
const dirX = dx / distance;
|
|
422
|
+
const dirY = dy / distance;
|
|
423
|
+
const halfW = width / 2;
|
|
424
|
+
const halfH = height / 2;
|
|
425
|
+
const tRight = dirX > 0 ? halfW / dirX : Infinity;
|
|
426
|
+
const tLeft = dirX < 0 ? -halfW / dirX : Infinity;
|
|
427
|
+
const tBottom = dirY > 0 ? halfH / dirY : Infinity;
|
|
428
|
+
const tTop = dirY < 0 ? -halfH / dirY : Infinity;
|
|
429
|
+
const t = Math.min(tRight, tLeft, tBottom, tTop);
|
|
430
|
+
return {
|
|
431
|
+
x: centerX - dirX * t,
|
|
432
|
+
y: centerY - dirY * t,
|
|
433
|
+
};
|
|
434
|
+
};
|
|
435
|
+
// Get dragged element bounds
|
|
436
|
+
const draggedRef = getElementRef(draggedElementId);
|
|
437
|
+
if (!draggedRef)
|
|
438
|
+
return;
|
|
439
|
+
const draggedBounds = draggedRef.getBoundingClientRect();
|
|
440
|
+
// Check proximity with all other elements
|
|
441
|
+
const allElements = [
|
|
442
|
+
{ id: 'logo' },
|
|
443
|
+
...copies.map((copy) => ({ id: `copy-${copy.id}` })),
|
|
444
|
+
];
|
|
445
|
+
const newProximityLines = [];
|
|
446
|
+
allElements.forEach(({ id }) => {
|
|
447
|
+
if (id === draggedElementId)
|
|
448
|
+
return;
|
|
449
|
+
const otherRef = getElementRef(id);
|
|
450
|
+
if (!otherRef)
|
|
451
|
+
return;
|
|
452
|
+
const otherBounds = otherRef.getBoundingClientRect();
|
|
453
|
+
// Calculate minimum distance between two rectangles (edge-to-edge)
|
|
454
|
+
// This is the same logic as detectProximityLines for green lines
|
|
455
|
+
const dx = Math.max(draggedBounds.left - otherBounds.right, otherBounds.left - draggedBounds.right, 0);
|
|
456
|
+
const dy = Math.max(draggedBounds.top - otherBounds.bottom, otherBounds.top - draggedBounds.bottom, 0);
|
|
457
|
+
const edgeDistance = Math.sqrt(dx * dx + dy * dy);
|
|
458
|
+
// Convert to unscaled pixels (same as detectProximityLines)
|
|
459
|
+
const edgeDistanceUnscaled = edgeDistance / sizeMultiplier;
|
|
460
|
+
// If within threshold, add proximity line
|
|
461
|
+
// But don't show if elements are touching (edgeDistanceUnscaled = 0)
|
|
462
|
+
if (edgeDistanceUnscaled <= proximityThreshold && edgeDistanceUnscaled > 0) {
|
|
463
|
+
// Get centers for border point calculation
|
|
464
|
+
const draggedCenter = getElementCenter(draggedElementId);
|
|
465
|
+
const otherCenter = getElementCenter(id);
|
|
466
|
+
if (draggedCenter && otherCenter) {
|
|
467
|
+
const fromPos = getBorderPoint(draggedElementId, otherCenter.x, otherCenter.y);
|
|
468
|
+
const toPos = getBorderPoint(id, draggedCenter.x, draggedCenter.y);
|
|
469
|
+
if (fromPos && toPos) {
|
|
470
|
+
// Use edge-to-edge distance for display (same as green line threshold)
|
|
471
|
+
const distance = Math.round(edgeDistanceUnscaled);
|
|
472
|
+
newProximityLines.push({
|
|
473
|
+
fromId: draggedElementId,
|
|
474
|
+
toId: id,
|
|
475
|
+
distance: distance,
|
|
476
|
+
fromPos,
|
|
477
|
+
toPos,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
setProximityLines(newProximityLines);
|
|
484
|
+
}, [logoRef, copyRefs, bannerContainerRef, copies, sizeMultiplier, getElementRef]);
|
|
485
|
+
return {
|
|
486
|
+
proximityLines,
|
|
487
|
+
setProximityLines,
|
|
488
|
+
detectProximityLines,
|
|
489
|
+
calculateProximityLines,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/BannerRenderer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BannerRenderer module exports
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BannerRenderer = void 0;
|
|
7
|
+
var BannerRenderer_1 = require("./BannerRenderer");
|
|
8
|
+
Object.defineProperty(exports, "BannerRenderer", { enumerable: true, get: function () { return BannerRenderer_1.BannerRenderer; } });
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* BannerRenderer
|
|
3
|
-
* Unified component that handles all banner styles based on configuration
|
|
2
|
+
* BannerRenderer types and interfaces
|
|
4
3
|
*/
|
|
5
|
-
import
|
|
6
|
-
import type {
|
|
7
|
-
|
|
4
|
+
import type { ImageProps, CopyConfig } from "../../types";
|
|
5
|
+
import type { AutoPositioningConfig, CopyElementConfig } from "../styles/types/substyleTypes";
|
|
6
|
+
/**
|
|
7
|
+
* Props for the BannerRenderer component
|
|
8
|
+
*/
|
|
9
|
+
export interface BannerRendererProps {
|
|
8
10
|
bannerStyle: number;
|
|
9
11
|
copies?: CopyConfig[];
|
|
10
12
|
bannerSubstyle?: number;
|
|
@@ -30,6 +32,21 @@ interface BannerRendererProps {
|
|
|
30
32
|
noiseIntensity?: number;
|
|
31
33
|
fontFamily?: string;
|
|
32
34
|
draggableMode?: boolean;
|
|
35
|
+
creationMode?: boolean;
|
|
36
|
+
linkingModeActive?: boolean;
|
|
37
|
+
onDebugPositions?: () => void;
|
|
38
|
+
onApplyAutoPositioning?: (config: {
|
|
39
|
+
config: AutoPositioningConfig;
|
|
40
|
+
gapRem: number;
|
|
41
|
+
copies?: Array<{
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
width?: number;
|
|
45
|
+
alignment?: string;
|
|
46
|
+
}>;
|
|
47
|
+
}) => void;
|
|
48
|
+
onConnectionsDeleted?: () => void;
|
|
49
|
+
onLineGapsChange?: (lineGaps: Record<string, number>) => void;
|
|
33
50
|
onLogoPositionChange?: (position: {
|
|
34
51
|
x: number;
|
|
35
52
|
y: number;
|
|
@@ -42,7 +59,11 @@ interface BannerRendererProps {
|
|
|
42
59
|
}) => void;
|
|
43
60
|
onCopyRotationChange?: (copyIndex: number, rotation: number) => void;
|
|
44
61
|
onCopyWidthChange?: (copyIndex: number, width: number) => void;
|
|
62
|
+
autoPositioningOverride?: {
|
|
63
|
+
enabled: boolean;
|
|
64
|
+
config?: AutoPositioningConfig;
|
|
65
|
+
gapRem?: number;
|
|
66
|
+
copies?: CopyElementConfig[];
|
|
67
|
+
};
|
|
45
68
|
}
|
|
46
|
-
|
|
47
|
-
export {};
|
|
48
|
-
//# sourceMappingURL=BannerRenderer.d.ts.map
|
|
69
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/BannerRenderer/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alignment utility functions for BannerRenderer
|
|
3
|
+
* Pure functions for calculating alignment guides between elements
|
|
4
|
+
*/
|
|
5
|
+
import type { RelativeBounds } from './snapUtils';
|
|
6
|
+
/**
|
|
7
|
+
* Represents an alignment line between two elements
|
|
8
|
+
*/
|
|
9
|
+
export interface AlignmentLine {
|
|
10
|
+
x?: number;
|
|
11
|
+
y?: number;
|
|
12
|
+
x1?: number;
|
|
13
|
+
x2?: number;
|
|
14
|
+
y1?: number;
|
|
15
|
+
y2?: number;
|
|
16
|
+
type: 'left' | 'center' | 'right' | 'top' | 'middle' | 'bottom';
|
|
17
|
+
orientation: 'vertical' | 'horizontal';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Calculate alignment lines between a dragged element and another element.
|
|
21
|
+
* Uses relative bounds (relative to container center).
|
|
22
|
+
*
|
|
23
|
+
* @param dragged - Relative bounds of the dragged element
|
|
24
|
+
* @param other - Relative bounds of the other element
|
|
25
|
+
* @param tolerance - Alignment tolerance in pixels (default: 0.5)
|
|
26
|
+
* @returns Array of alignment lines
|
|
27
|
+
*/
|
|
28
|
+
export declare function calculateAlignmentLinesBetween(dragged: RelativeBounds, other: RelativeBounds, tolerance?: number): AlignmentLine[];
|
|
29
|
+
/**
|
|
30
|
+
* Calculate all alignment lines between a dragged element and multiple other elements.
|
|
31
|
+
*
|
|
32
|
+
* @param dragged - Relative bounds of the dragged element
|
|
33
|
+
* @param others - Array of relative bounds of other elements
|
|
34
|
+
* @param tolerance - Alignment tolerance in pixels (default: 0.5)
|
|
35
|
+
* @returns Array of all alignment lines
|
|
36
|
+
*/
|
|
37
|
+
export declare function calculateAllAlignmentLines(dragged: RelativeBounds, others: RelativeBounds[], tolerance?: number): AlignmentLine[];
|
|
38
|
+
//# sourceMappingURL=alignmentUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alignmentUtils.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/utils/alignmentUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAChE,WAAW,EAAE,UAAU,GAAG,YAAY,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,cAAc,EACrB,SAAS,SAAM,GACd,aAAa,EAAE,CAoHjB;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,cAAc,EAAE,EACxB,SAAS,SAAM,GACd,aAAa,EAAE,CAQjB"}
|