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.
Files changed (117) hide show
  1. package/README.md +228 -131
  2. package/dist/components/BannerRenderer/BannerRenderer.d.ts +8 -0
  3. package/dist/components/BannerRenderer/BannerRenderer.d.ts.map +1 -0
  4. package/dist/components/BannerRenderer/BannerRenderer.js +325 -0
  5. package/dist/components/BannerRenderer/components/CopyElement.d.ts +62 -0
  6. package/dist/components/BannerRenderer/components/CopyElement.d.ts.map +1 -0
  7. package/dist/components/BannerRenderer/components/CopyElement.js +220 -0
  8. package/dist/components/BannerRenderer/components/InteractiveLines.d.ts +26 -0
  9. package/dist/components/BannerRenderer/components/InteractiveLines.d.ts.map +1 -0
  10. package/dist/components/BannerRenderer/components/InteractiveLines.js +172 -0
  11. package/dist/components/BannerRenderer/components/LogoElement.d.ts +55 -0
  12. package/dist/components/BannerRenderer/components/LogoElement.d.ts.map +1 -0
  13. package/dist/components/BannerRenderer/components/LogoElement.js +53 -0
  14. package/dist/components/BannerRenderer/components/VisualGuides.d.ts +43 -0
  15. package/dist/components/BannerRenderer/components/VisualGuides.d.ts.map +1 -0
  16. package/dist/components/BannerRenderer/components/VisualGuides.js +110 -0
  17. package/dist/components/BannerRenderer/components/index.d.ts +12 -0
  18. package/dist/components/BannerRenderer/components/index.d.ts.map +1 -0
  19. package/dist/components/BannerRenderer/components/index.js +14 -0
  20. package/dist/components/BannerRenderer/constants.d.ts +15 -0
  21. package/dist/components/BannerRenderer/constants.d.ts.map +1 -0
  22. package/dist/components/BannerRenderer/constants.js +36 -0
  23. package/dist/components/BannerRenderer/hooks/index.d.ts +14 -0
  24. package/dist/components/BannerRenderer/hooks/index.d.ts.map +1 -0
  25. package/dist/components/BannerRenderer/hooks/index.js +16 -0
  26. package/dist/components/BannerRenderer/hooks/useAutoPositioning/debugPositions.d.ts +30 -0
  27. package/dist/components/BannerRenderer/hooks/useAutoPositioning/debugPositions.d.ts.map +1 -0
  28. package/dist/components/BannerRenderer/hooks/useAutoPositioning/debugPositions.js +87 -0
  29. package/dist/components/BannerRenderer/hooks/useAutoPositioning/index.d.ts +13 -0
  30. package/dist/components/BannerRenderer/hooks/useAutoPositioning/index.d.ts.map +1 -0
  31. package/dist/components/BannerRenderer/hooks/useAutoPositioning/index.js +21 -0
  32. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAnchorEdgeLocking.d.ts +71 -0
  33. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAnchorEdgeLocking.d.ts.map +1 -0
  34. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAnchorEdgeLocking.js +151 -0
  35. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAutoPositioningMain.d.ts +66 -0
  36. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAutoPositioningMain.d.ts.map +1 -0
  37. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useAutoPositioningMain.js +332 -0
  38. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useChainPositioning.d.ts +61 -0
  39. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useChainPositioning.d.ts.map +1 -0
  40. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useChainPositioning.js +180 -0
  41. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useHeightCompensation.d.ts +60 -0
  42. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useHeightCompensation.d.ts.map +1 -0
  43. package/dist/components/BannerRenderer/hooks/useAutoPositioning/useHeightCompensation.js +178 -0
  44. package/dist/components/BannerRenderer/hooks/useAutoPositioning.d.ts +8 -0
  45. package/dist/components/BannerRenderer/hooks/useAutoPositioning.d.ts.map +1 -0
  46. package/dist/components/BannerRenderer/hooks/useAutoPositioning.js +12 -0
  47. package/dist/components/BannerRenderer/hooks/useDragSnap.d.ts +30 -0
  48. package/dist/components/BannerRenderer/hooks/useDragSnap.d.ts.map +1 -0
  49. package/dist/components/BannerRenderer/hooks/useDragSnap.js +90 -0
  50. package/dist/components/BannerRenderer/hooks/useElementRefs.d.ts +22 -0
  51. package/dist/components/BannerRenderer/hooks/useElementRefs.d.ts.map +1 -0
  52. package/dist/components/BannerRenderer/hooks/useElementRefs.js +70 -0
  53. package/dist/components/BannerRenderer/hooks/useLineDrawing.d.ts +40 -0
  54. package/dist/components/BannerRenderer/hooks/useLineDrawing.d.ts.map +1 -0
  55. package/dist/components/BannerRenderer/hooks/useLineDrawing.js +198 -0
  56. package/dist/components/BannerRenderer/hooks/useProximityDetection.d.ts +43 -0
  57. package/dist/components/BannerRenderer/hooks/useProximityDetection.d.ts.map +1 -0
  58. package/dist/components/BannerRenderer/hooks/useProximityDetection.js +491 -0
  59. package/dist/components/BannerRenderer/index.d.ts +6 -0
  60. package/dist/components/BannerRenderer/index.d.ts.map +1 -0
  61. package/dist/components/BannerRenderer/index.js +8 -0
  62. package/dist/components/{BannerRenderer.d.ts → BannerRenderer/types.d.ts} +29 -8
  63. package/dist/components/BannerRenderer/types.d.ts.map +1 -0
  64. package/dist/components/BannerRenderer/types.js +5 -0
  65. package/dist/components/BannerRenderer/utils/alignmentUtils.d.ts +38 -0
  66. package/dist/components/BannerRenderer/utils/alignmentUtils.d.ts.map +1 -0
  67. package/dist/components/BannerRenderer/utils/alignmentUtils.js +138 -0
  68. package/dist/components/BannerRenderer/utils/elementCheckUtils.d.ts +22 -0
  69. package/dist/components/BannerRenderer/utils/elementCheckUtils.d.ts.map +1 -0
  70. package/dist/components/BannerRenderer/utils/elementCheckUtils.js +37 -0
  71. package/dist/components/BannerRenderer/utils/elementIdUtils.d.ts +25 -0
  72. package/dist/components/BannerRenderer/utils/elementIdUtils.d.ts.map +1 -0
  73. package/dist/components/BannerRenderer/utils/elementIdUtils.js +56 -0
  74. package/dist/components/BannerRenderer/utils/fontUtils.d.ts +12 -0
  75. package/dist/components/BannerRenderer/utils/fontUtils.d.ts.map +1 -0
  76. package/dist/components/BannerRenderer/utils/fontUtils.js +26 -0
  77. package/dist/components/BannerRenderer/utils/graphUtils.d.ts +54 -0
  78. package/dist/components/BannerRenderer/utils/graphUtils.d.ts.map +1 -0
  79. package/dist/components/BannerRenderer/utils/graphUtils.js +138 -0
  80. package/dist/components/BannerRenderer/utils/index.d.ts +12 -0
  81. package/dist/components/BannerRenderer/utils/index.d.ts.map +1 -0
  82. package/dist/components/BannerRenderer/utils/index.js +27 -0
  83. package/dist/components/BannerRenderer/utils/snapUtils.d.ts +38 -0
  84. package/dist/components/BannerRenderer/utils/snapUtils.d.ts.map +1 -0
  85. package/dist/components/BannerRenderer/utils/snapUtils.js +109 -0
  86. package/dist/components/BannerVisor.d.ts.map +1 -1
  87. package/dist/components/BannerVisor.js +8 -1
  88. package/dist/components/index.js +1 -1
  89. package/dist/components/shared/DraggableElement.d.ts +11 -0
  90. package/dist/components/shared/DraggableElement.d.ts.map +1 -1
  91. package/dist/components/shared/DraggableElement.js +47 -51
  92. package/dist/components/styles/Style1/substyleConfig.d.ts.map +1 -1
  93. package/dist/components/styles/Style1/substyleConfig.js +53 -54
  94. package/dist/components/styles/Style2/substyleConfig.js +78 -78
  95. package/dist/components/styles/Style3/substyleConfig.d.ts.map +1 -1
  96. package/dist/components/styles/Style3/substyleConfig.js +40 -37
  97. package/dist/components/styles/Style4/substyleConfig.js +57 -57
  98. package/dist/components/styles/types/substyleTypes.d.ts +32 -15
  99. package/dist/components/styles/types/substyleTypes.d.ts.map +1 -1
  100. package/dist/components/styles/utils/chainValidation.d.ts +41 -0
  101. package/dist/components/styles/utils/chainValidation.d.ts.map +1 -0
  102. package/dist/components/styles/utils/chainValidation.js +148 -0
  103. package/dist/components/styles/utils/positioningUtils.d.ts +207 -11
  104. package/dist/components/styles/utils/positioningUtils.d.ts.map +1 -1
  105. package/dist/components/styles/utils/positioningUtils.js +520 -19
  106. package/dist/constants/characterLimits.d.ts +4 -16
  107. package/dist/constants/characterLimits.d.ts.map +1 -1
  108. package/dist/constants/characterLimits.js +28 -26
  109. package/dist/constants/styleConfigs.js +6 -6
  110. package/dist/styleConfig.d.ts +4 -4
  111. package/dist/styleConfig.d.ts.map +1 -1
  112. package/dist/styleConfig.js +8 -16
  113. package/dist/types.d.ts +42 -0
  114. package/dist/types.d.ts.map +1 -1
  115. package/package.json +1 -1
  116. package/dist/components/BannerRenderer.d.ts.map +0 -1
  117. package/dist/components/BannerRenderer.js +0 -559
@@ -5,8 +5,28 @@
5
5
  * Adapted for absolute positioning system (x, y coordinates from center)
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.calculateAutoPositionOffset = exports.calculateDownOffset = exports.calculateUpOffset = void 0;
8
+ exports.calculateSingleLinkOffset = exports.calculateDownOffset = exports.calculateUpOffset = void 0;
9
+ exports.getElementRef = getElementRef;
10
+ exports.getCopyIndexFromElementId = getCopyIndexFromElementId;
11
+ exports.hasElementCenterOrigin = hasElementCenterOrigin;
12
+ exports.checkElementEdgeProximity = checkElementEdgeProximity;
13
+ exports.calculateChainedOffsets = calculateChainedOffsets;
14
+ exports.detectNearestEdge = detectNearestEdge;
15
+ exports.calculateGapToEdge = calculateGapToEdge;
16
+ exports.orderChainFromAnchor = orderChainFromAnchor;
17
+ exports.getSubsequentElementsInChain = getSubsequentElementsInChain;
18
+ exports.calculateAbsoluteChainPositions = calculateAbsoluteChainPositions;
19
+ exports.calculateTargetPositionsFromAnchor = calculateTargetPositionsFromAnchor;
20
+ exports.getCopyData = getCopyData;
21
+ exports.calculateAnchorHeightCompensation = calculateAnchorHeightCompensation;
22
+ exports.calculateTargetCompensationForAnchorGrowth = calculateTargetCompensationForAnchorGrowth;
23
+ exports.calculateTargetSelfCompensation = calculateTargetSelfCompensation;
24
+ exports.calculateSubsequentCompensation = calculateSubsequentCompensation;
25
+ exports.captureAnchorEdgeConfig = captureAnchorEdgeConfig;
26
+ exports.measureElementHeights = measureElementHeights;
27
+ exports.mapsAreEqual = mapsAreEqual;
9
28
  const defaults_1 = require("../../../constants/defaults");
29
+ const chainValidation_1 = require("./chainValidation");
10
30
  /**
11
31
  * Calculate auto-positioning offset for 'up' direction
12
32
  * Target element will be positioned above the anchor with a gap
@@ -14,14 +34,17 @@ const defaults_1 = require("../../../constants/defaults");
14
34
  * @param anchorHeight - Height of anchor element in pixels
15
35
  * @param targetHeight - Height of target element in pixels
16
36
  * @param anchorHasCenterOrigin - Whether anchor is positioned from center (true) or top-left (false)
37
+ * @param fixAnchorBottomEdge - If true, anchor's bottom edge position is fixed (grows upward)
17
38
  * @returns Offset in pixels (negative value to move up)
18
39
  */
19
- const calculateUpOffset = (gapRem, anchorHeight, targetHeight, anchorHasCenterOrigin) => {
40
+ const calculateUpOffset = (gapRem, anchorHeight, targetHeight, anchorHasCenterOrigin, fixAnchorBottomEdge = false) => {
20
41
  const gapPixels = gapRem * defaults_1.REM_TO_PIXELS;
21
42
  // Target always has centerOrigin=true (positioned from center)
22
43
  const targetOffset = targetHeight / 2;
23
44
  if (anchorHasCenterOrigin) {
24
45
  // Anchor positioned from center: offset from center to center
46
+ // This calculation is the same regardless of edge fixing
47
+ // Edge fixing is handled by adjusting the anchor's position, not the offset
25
48
  return -((anchorHeight / 2) + gapPixels + targetOffset);
26
49
  }
27
50
  else {
@@ -37,14 +60,17 @@ exports.calculateUpOffset = calculateUpOffset;
37
60
  * @param anchorHeight - Height of anchor element in pixels
38
61
  * @param targetHeight - Height of target element in pixels
39
62
  * @param anchorHasCenterOrigin - Whether anchor is positioned from center (true) or top-left (false)
63
+ * @param fixAnchorTopEdge - If true, anchor's top edge position is fixed (grows downward)
40
64
  * @returns Offset in pixels (positive value to move down)
41
65
  */
42
- const calculateDownOffset = (gapRem, anchorHeight, targetHeight, anchorHasCenterOrigin) => {
66
+ const calculateDownOffset = (gapRem, anchorHeight, targetHeight, anchorHasCenterOrigin, fixAnchorTopEdge = false) => {
43
67
  const gapPixels = gapRem * defaults_1.REM_TO_PIXELS;
44
68
  // Target always has centerOrigin=true (positioned from center)
45
69
  const targetOffset = targetHeight / 2;
46
70
  if (anchorHasCenterOrigin) {
47
71
  // Anchor positioned from center: offset from center to center
72
+ // This calculation is the same regardless of edge fixing
73
+ // Edge fixing is handled by adjusting the anchor's position, not the offset
48
74
  return (anchorHeight / 2) + gapPixels + targetOffset;
49
75
  }
50
76
  else {
@@ -54,26 +80,501 @@ const calculateDownOffset = (gapRem, anchorHeight, targetHeight, anchorHasCenter
54
80
  };
55
81
  exports.calculateDownOffset = calculateDownOffset;
56
82
  /**
57
- * Calculate auto-positioning offset based on direction
58
- * Works with absolute positioning system where elements have x, y coordinates from center
59
- * @param config - Substyle configuration
60
- * @param autoConfig - Auto-positioning configuration
61
- * @param anchorHeight - Height of anchor element in pixels
62
- * @param targetHeight - Height of target element in pixels
63
- * @param anchorHasCenterOrigin - Whether anchor is positioned from center (true) or top-left (false)
64
- * @returns Offset in pixels (Y-axis only for now)
83
+ * Calculate offset for a single link in the chain
65
84
  */
66
- const calculateAutoPositionOffset = (config, autoConfig, anchorHeight, targetHeight, anchorHasCenterOrigin = true) => {
67
- var _a;
68
- const { direction } = autoConfig;
69
- const gapRem = (_a = config.gapRem) !== null && _a !== void 0 ? _a : 0;
85
+ const calculateSingleLinkOffset = (direction, gapRem, fromHeight, toHeight, fromHasCenterOrigin, fromIsAtBottomEdge) => {
70
86
  if (direction === 'up') {
71
- return (0, exports.calculateUpOffset)(gapRem, anchorHeight, targetHeight, anchorHasCenterOrigin);
87
+ return (0, exports.calculateUpOffset)(gapRem, fromHeight, toHeight, fromHasCenterOrigin, fromIsAtBottomEdge);
72
88
  }
73
89
  else if (direction === 'down') {
74
- return (0, exports.calculateDownOffset)(gapRem, anchorHeight, targetHeight, anchorHasCenterOrigin);
90
+ const fromIsAtTopEdge = !fromIsAtBottomEdge;
91
+ return (0, exports.calculateDownOffset)(gapRem, fromHeight, toHeight, fromHasCenterOrigin, fromIsAtTopEdge);
75
92
  }
76
- // Note: left/right directions would need X-axis offset (not implemented yet, only Y-axis)
93
+ // Note: left/right would need X-axis offset (not implemented yet)
77
94
  return 0;
78
95
  };
79
- exports.calculateAutoPositionOffset = calculateAutoPositionOffset;
96
+ exports.calculateSingleLinkOffset = calculateSingleLinkOffset;
97
+ /**
98
+ * Get element ref from element ID
99
+ * Supports both copy-{uuid} and copy-{N} (styleSlot) formats
100
+ */
101
+ function getElementRef(elementId, refs, copies) {
102
+ if (elementId === 'logo') {
103
+ return refs.logo;
104
+ }
105
+ else if (elementId.startsWith('copy-')) {
106
+ const suffix = elementId.substring(5); // Remove 'copy-' prefix
107
+ // Check if it's copy-N format (just a number = styleSlot)
108
+ if (/^\d+$/.test(suffix)) {
109
+ const styleSlotIndex = parseInt(suffix, 10);
110
+ // First try: find copy by styleSlot
111
+ const copy = copies.find(c => c.styleSlot === styleSlotIndex);
112
+ if (copy) {
113
+ const copyIndex = copies.indexOf(copy);
114
+ if (copyIndex < refs.copies.length) {
115
+ return refs.copies[copyIndex];
116
+ }
117
+ }
118
+ // Fallback: use direct array index
119
+ if (styleSlotIndex < copies.length && styleSlotIndex < refs.copies.length) {
120
+ return refs.copies[styleSlotIndex];
121
+ }
122
+ }
123
+ else {
124
+ // It's a UUID format - find by id
125
+ const copyIndex = copies.findIndex(c => c.id === suffix);
126
+ if (copyIndex !== -1 && copyIndex < refs.copies.length) {
127
+ return refs.copies[copyIndex];
128
+ }
129
+ }
130
+ return null;
131
+ }
132
+ return null;
133
+ }
134
+ /**
135
+ * Get copy index from element ID
136
+ */
137
+ function getCopyIndexFromElementId(elementId, copies) {
138
+ if (elementId === 'logo') {
139
+ return undefined;
140
+ }
141
+ else if (elementId.startsWith('copy-')) {
142
+ // DYNAMIC: Handle 'copy-N' format where N is the styleSlot
143
+ const styleSlotIndex = parseInt(elementId.replace('copy-', ''));
144
+ const copyIndex = copies.findIndex(c => c.styleSlot === styleSlotIndex);
145
+ // FIX: Return the array index, not the styleSlot
146
+ // onCopyPositionChange expects the array index to update the correct copy
147
+ return copyIndex !== -1 ? copyIndex : styleSlotIndex;
148
+ }
149
+ return undefined;
150
+ }
151
+ /**
152
+ * Check if element has center origin (all copies do, logo doesn't)
153
+ */
154
+ function hasElementCenterOrigin(elementId) {
155
+ return elementId !== 'logo';
156
+ }
157
+ /**
158
+ * Check if element is closest to bottom edge (for compensation)
159
+ */
160
+ function checkElementEdgeProximity(elementId, elementRef, bannerContainerRef, sizeMultiplier) {
161
+ if (!bannerContainerRef)
162
+ return false;
163
+ const bannerBounds = bannerContainerRef.getBoundingClientRect();
164
+ const elementBounds = elementRef.getBoundingClientRect();
165
+ const bannerHeight = bannerBounds.height / sizeMultiplier;
166
+ // Calculate element's Y position relative to banner center
167
+ const elementCenterY = (elementBounds.top + elementBounds.height / 2 - bannerBounds.top - bannerBounds.height / 2) / sizeMultiplier;
168
+ // Calculate distance to top and bottom edges
169
+ const distToTop = Math.abs(elementCenterY + bannerHeight / 2);
170
+ const distToBottom = Math.abs(elementCenterY - bannerHeight / 2);
171
+ // Element is closest to bottom if distance to bottom < distance to top
172
+ return distToBottom < distToTop;
173
+ }
174
+ /**
175
+ * Calculate offsets for all elements in a positioning chain
176
+ * Supports cascading offsets where each element's position depends on its parent
177
+ *
178
+ * @param config - Substyle configuration
179
+ * @param links - Array of positioning links defining the chain
180
+ * @param copies - Array of copy configurations
181
+ * @param refs - Object containing refs to logo and copy elements
182
+ * @param sizeMultiplier - Canvas scaling factor
183
+ * @param elementCompensations - Record of height-based compensations per element
184
+ * @param bannerContainerRef - Ref to banner container for edge detection
185
+ * @returns Record mapping copy index to Y offset in pixels
186
+ */
187
+ function calculateChainedOffsets(config, links, copies, refs, sizeMultiplier, elementCompensations, bannerContainerRef) {
188
+ var _a, _b;
189
+ console.log('📊 calculateChainedOffsets START', { links, copiesCount: copies.length });
190
+ // Validate configuration
191
+ const validation = (0, chainValidation_1.validateChainConfiguration)(links);
192
+ if (!validation.valid) {
193
+ console.log('❌ Chain validation FAILED:', validation.error);
194
+ return {};
195
+ }
196
+ console.log('✅ Chain validation passed');
197
+ // Build graph and get calculation order
198
+ const graph = (0, chainValidation_1.buildDependencyGraph)(links);
199
+ const calculationOrder = (0, chainValidation_1.topologicalSort)(graph);
200
+ console.log('📋 Calculation order:', calculationOrder);
201
+ // Track accumulated offsets for cascading
202
+ const accumulatedOffsets = {};
203
+ const offsets = {};
204
+ // Process each element in topological order
205
+ for (const elementId of calculationOrder) {
206
+ // Find incoming link (the link where this element is the "to")
207
+ const incomingLink = (0, chainValidation_1.findIncomingLink)(links, elementId);
208
+ if (!incomingLink) {
209
+ // This is a root/anchor element - no offset
210
+ console.log(`🔗 ${elementId}: ROOT/ANCHOR (no incoming link)`);
211
+ accumulatedOffsets[elementId] = 0;
212
+ continue;
213
+ }
214
+ // Get refs for from and to elements
215
+ const fromRef = getElementRef(incomingLink.fromElement, refs, copies);
216
+ const toRef = getElementRef(elementId, refs, copies);
217
+ console.log(`🔗 ${elementId}: fromRef=${!!fromRef}, toRef=${!!toRef}`);
218
+ if (!fromRef || !toRef) {
219
+ console.log(`⚠️ ${elementId}: SKIPPED - missing ref`);
220
+ continue;
221
+ }
222
+ // Measure heights
223
+ const fromHeight = fromRef.getBoundingClientRect().height / sizeMultiplier;
224
+ const toHeight = toRef.getBoundingClientRect().height / sizeMultiplier;
225
+ // Get gap (link-specific or global)
226
+ const gapRem = (_b = (_a = incomingLink.gapRem) !== null && _a !== void 0 ? _a : config.gapRem) !== null && _b !== void 0 ? _b : 0;
227
+ // Check element properties
228
+ const fromHasCenterOrigin = hasElementCenterOrigin(incomingLink.fromElement);
229
+ const fromIsAtBottomEdge = checkElementEdgeProximity(incomingLink.fromElement, fromRef, bannerContainerRef, sizeMultiplier);
230
+ // Calculate base offset for this link
231
+ const baseOffset = (0, exports.calculateSingleLinkOffset)(incomingLink.direction, gapRem, fromHeight, toHeight, fromHasCenterOrigin, fromIsAtBottomEdge);
232
+ // Get accumulated offset of from element (cascading)
233
+ const fromAccumulatedOffset = accumulatedOffsets[incomingLink.fromElement] || 0;
234
+ // Get ANCHOR's compensation - needed for correct initial offset calculation
235
+ // This makes totalOffset = originalBaseOffset (before height change)
236
+ const fromCompensation = elementCompensations[incomingLink.fromElement] || 0;
237
+ // Total offset = base + cascade + anchor compensation
238
+ // The compensation neutralizes the height increase in baseOffset
239
+ const totalOffset = baseOffset + fromAccumulatedOffset + fromCompensation;
240
+ console.log(`📐 ${elementId}: baseOffset=${baseOffset.toFixed(2)}, fromAccum=${fromAccumulatedOffset.toFixed(2)}, fromComp=${fromCompensation.toFixed(2)}, TOTAL=${totalOffset.toFixed(2)}`);
241
+ // Store accumulated offset for this element
242
+ accumulatedOffsets[elementId] = totalOffset;
243
+ // Map to copy index for state storage
244
+ const copyIndex = getCopyIndexFromElementId(elementId, copies);
245
+ console.log(`📌 ${elementId}: copyIndex=${copyIndex}`);
246
+ if (copyIndex !== undefined) {
247
+ offsets[copyIndex] = totalOffset;
248
+ }
249
+ }
250
+ console.log('📊 calculateChainedOffsets RESULT:', offsets);
251
+ return offsets;
252
+ }
253
+ /**
254
+ * Detect which edge (top or bottom) the element is closest to
255
+ */
256
+ function detectNearestEdge(element, container, sizeMultiplier) {
257
+ const containerBounds = container.getBoundingClientRect();
258
+ const elementBounds = element.getBoundingClientRect();
259
+ const containerHeight = containerBounds.height / sizeMultiplier;
260
+ const elementCenterY = (elementBounds.top + elementBounds.height / 2 - containerBounds.top) / sizeMultiplier;
261
+ const distToTop = elementCenterY;
262
+ const distToBottom = containerHeight - elementCenterY;
263
+ const edge = distToBottom < distToTop ? 'bottom' : 'top';
264
+ // Debug log - uncomment for troubleshooting
265
+ // console.log(`🔍 detectNearestEdge: containerHeight=${containerHeight.toFixed(2)}, elementCenterY=${elementCenterY.toFixed(2)}, distToTop=${distToTop.toFixed(2)}, distToBottom=${distToBottom.toFixed(2)}, edge=${edge}`);
266
+ return edge;
267
+ }
268
+ /**
269
+ * Calculate the gap from an element's edge to the container's edge
270
+ */
271
+ function calculateGapToEdge(element, edge, container, sizeMultiplier) {
272
+ const containerBounds = container.getBoundingClientRect();
273
+ const elementBounds = element.getBoundingClientRect();
274
+ const containerHeight = containerBounds.height / sizeMultiplier;
275
+ const elementTop = (elementBounds.top - containerBounds.top) / sizeMultiplier;
276
+ const elementBottom = (elementBounds.bottom - containerBounds.top) / sizeMultiplier;
277
+ if (edge === 'bottom') {
278
+ // Gap from element's bottom edge to container's bottom edge
279
+ return containerHeight - elementBottom;
280
+ }
281
+ else {
282
+ // Gap from element's top edge to container's top edge
283
+ return elementTop;
284
+ }
285
+ }
286
+ /**
287
+ * Order targets in chain from anchor to last element
288
+ */
289
+ function orderChainFromAnchor(anchorId, links) {
290
+ const ordered = [];
291
+ let currentId = anchorId;
292
+ while (true) {
293
+ const nextLink = links.find(l => l.from === currentId);
294
+ if (!nextLink)
295
+ break;
296
+ ordered.push(nextLink.to);
297
+ currentId = nextLink.to;
298
+ }
299
+ return ordered;
300
+ }
301
+ /**
302
+ * Get all elements that come AFTER a given element in the chain
303
+ * Useful for determining which elements need to move when an element's height changes
304
+ */
305
+ function getSubsequentElementsInChain(elementId, links) {
306
+ const subsequent = [];
307
+ let currentId = elementId;
308
+ while (true) {
309
+ const nextLink = links.find(l => l.from === currentId);
310
+ if (!nextLink)
311
+ break;
312
+ subsequent.push(nextLink.to);
313
+ currentId = nextLink.to;
314
+ }
315
+ return subsequent;
316
+ }
317
+ /**
318
+ * Calculate absolute Y positions for all elements in a chain
319
+ * based on the anchor's fixed edge position
320
+ */
321
+ function calculateAbsoluteChainPositions(bannerHeight, chainConfig, elementHeights) {
322
+ var _a;
323
+ const positions = {};
324
+ const { anchorId, anchorEdge, anchorGapToEdge, links } = chainConfig;
325
+ const anchorHeight = elementHeights[anchorId] || 0;
326
+ // Debug log - uncomment for troubleshooting
327
+ // console.log(`🎯 calculateAbsoluteChainPositions: anchorId=${anchorId}, edge=${anchorEdge}, gapToEdge=${anchorGapToEdge.toFixed(2)}, anchorHeight=${anchorHeight.toFixed(2)}`);
328
+ // 1. Calculate anchor's center Y position (relative to banner center, where 0 = center)
329
+ let anchorCenterY;
330
+ if (anchorEdge === 'bottom') {
331
+ // ANCHOR's bottom edge stays at: (bannerHeight/2) - anchorGapToEdge
332
+ // ANCHOR's center is at: bottomEdge - anchorHeight/2
333
+ // In center-origin coords: (bannerHeight/2 - anchorGapToEdge - anchorHeight/2) - bannerHeight/2
334
+ // = -anchorGapToEdge - anchorHeight/2
335
+ // But we need to express as offset from banner center for the y coordinate
336
+ // Actually, y=0 is banner center, y>0 is down
337
+ // Bottom edge of banner is at y = bannerHeight/2 (not scaled, in banner coords)
338
+ // ANCHOR bottom should be at: bannerHeight/2 - anchorGapToEdge (from center)
339
+ // ANCHOR center should be at: bannerHeight/2 - anchorGapToEdge - anchorHeight/2
340
+ anchorCenterY = (bannerHeight / 2) - anchorGapToEdge - (anchorHeight / 2);
341
+ }
342
+ else {
343
+ // ANCHOR's top edge stays at: -(bannerHeight/2) + anchorGapToEdge
344
+ // ANCHOR's center is at: topEdge + anchorHeight/2
345
+ anchorCenterY = -(bannerHeight / 2) + anchorGapToEdge + (anchorHeight / 2);
346
+ }
347
+ positions[anchorId] = anchorCenterY;
348
+ console.log(`📍 ANCHOR ${anchorId}: centerY=${anchorCenterY.toFixed(2)}`);
349
+ // 2. Calculate positions for targets (grow in opposite direction from edge)
350
+ const direction = anchorEdge === 'bottom' ? -1 : 1; // -1 = up, 1 = down
351
+ const orderedTargets = orderChainFromAnchor(anchorId, links);
352
+ let prevElementId = anchorId;
353
+ let prevCenterY = anchorCenterY;
354
+ for (const targetId of orderedTargets) {
355
+ const link = links.find(l => l.from === prevElementId && l.to === targetId);
356
+ const gapPx = ((_a = link === null || link === void 0 ? void 0 : link.gapRem) !== null && _a !== void 0 ? _a : 0) * defaults_1.REM_TO_PIXELS;
357
+ const prevHeight = elementHeights[prevElementId] || 0;
358
+ const targetHeight = elementHeights[targetId] || 0;
359
+ // Target center = prev center + direction * (prev half height + gap + target half height)
360
+ const targetCenterY = prevCenterY + direction * ((prevHeight / 2) + gapPx + (targetHeight / 2));
361
+ positions[targetId] = targetCenterY;
362
+ // Debug log - uncomment for troubleshooting
363
+ // console.log(`📍 TARGET ${targetId}: centerY=${targetCenterY.toFixed(2)} (gap=${gapPx.toFixed(2)}, prevHeight=${prevHeight.toFixed(2)}, targetHeight=${targetHeight.toFixed(2)})`);
364
+ prevElementId = targetId;
365
+ prevCenterY = targetCenterY;
366
+ }
367
+ return positions;
368
+ }
369
+ /**
370
+ * Calculate target positions based on CURRENT anchor position from DOM
371
+ * This avoids the issue where recalculating anchorCenterY from anchorGapToEdge
372
+ * can produce different results than the actual DOM position
373
+ */
374
+ function calculateTargetPositionsFromAnchor(anchorRef, bannerContainerRef, sizeMultiplier, links, elementHeights, anchorId) {
375
+ var _a;
376
+ const positions = {};
377
+ // Get ANCHOR's current center Y directly from DOM (relative to banner center)
378
+ const bannerBounds = bannerContainerRef.getBoundingClientRect();
379
+ const anchorBounds = anchorRef.getBoundingClientRect();
380
+ const bannerCenterY = bannerBounds.top + bannerBounds.height / 2;
381
+ const anchorCenterY = ((anchorBounds.top + anchorBounds.height / 2) - bannerCenterY) / sizeMultiplier;
382
+ positions[anchorId] = anchorCenterY;
383
+ console.log(`📍 ANCHOR ${anchorId}: centerY=${anchorCenterY.toFixed(2)} (from DOM)`);
384
+ // Detect direction based on anchor's position relative to banner center
385
+ // If anchor is below center (positive Y), targets grow UP (negative direction)
386
+ // If anchor is above center (negative Y), targets grow DOWN (positive direction)
387
+ const direction = anchorCenterY > 0 ? -1 : 1;
388
+ // Order targets and calculate their positions
389
+ const orderedTargets = orderChainFromAnchor(anchorId, links);
390
+ let prevElementId = anchorId;
391
+ let prevCenterY = anchorCenterY;
392
+ for (const targetId of orderedTargets) {
393
+ const link = links.find(l => l.from === prevElementId && l.to === targetId);
394
+ const gapPx = ((_a = link === null || link === void 0 ? void 0 : link.gapRem) !== null && _a !== void 0 ? _a : 0) * defaults_1.REM_TO_PIXELS;
395
+ const prevHeight = elementHeights[prevElementId] || 0;
396
+ const targetHeight = elementHeights[targetId] || 0;
397
+ // Target center = prev center + direction * (prev half height + gap + target half height)
398
+ const targetCenterY = prevCenterY + direction * ((prevHeight / 2) + gapPx + (targetHeight / 2));
399
+ positions[targetId] = targetCenterY;
400
+ // Debug log - uncomment for troubleshooting
401
+ // console.log(`📍 TARGET ${targetId}: centerY=${targetCenterY.toFixed(2)} (gap=${gapPx.toFixed(2)}, direction=${direction})`);
402
+ prevElementId = targetId;
403
+ prevCenterY = targetCenterY;
404
+ }
405
+ return positions;
406
+ }
407
+ /**
408
+ * Get copy/logo data for positioning calculations
409
+ * Extracts position and dimension data from a copy or logo element
410
+ *
411
+ * @param elementName - Element identifier ('logo' or 'copy-N')
412
+ * @param copies - Array of copy configurations
413
+ * @param config - Substyle configuration containing base positions
414
+ * @param logoTranslateX - Logo X translation
415
+ * @param logoTranslateY - Logo Y translation
416
+ * @param logoWidth - Optional logo width
417
+ * @returns Position and dimension data, or null if element not found
418
+ */
419
+ function getCopyData(elementName, copies, config, logoTranslateX, logoTranslateY, logoWidth) {
420
+ var _a, _b, _c;
421
+ if (elementName === 'logo') {
422
+ return {
423
+ x: logoTranslateX,
424
+ y: logoTranslateY,
425
+ width: logoWidth || 0,
426
+ element: 'logo'
427
+ };
428
+ }
429
+ const copyMatch = elementName.match(/^copy-(\d+)$/);
430
+ if (copyMatch) {
431
+ const styleSlotIndex = parseInt(copyMatch[1], 10);
432
+ const copy = copies.find(c => c.styleSlot === styleSlotIndex) || copies[styleSlotIndex];
433
+ if (!copy) {
434
+ return null;
435
+ }
436
+ const copyConfig = (_a = config.copies) === null || _a === void 0 ? void 0 : _a[styleSlotIndex];
437
+ const baseX = (_b = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.x) !== null && _b !== void 0 ? _b : 0;
438
+ const baseY = (_c = copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.y) !== null && _c !== void 0 ? _c : 0;
439
+ return {
440
+ x: baseX + (copy.translateX || 0),
441
+ y: baseY + (copy.translateY || 0),
442
+ width: copy.width || (copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.width) || 0,
443
+ alignment: copy.align || (copyConfig === null || copyConfig === void 0 ? void 0 : copyConfig.alignment),
444
+ element: elementName
445
+ };
446
+ }
447
+ return null;
448
+ }
449
+ // ============================================================================
450
+ // Height Compensation Functions
451
+ // ============================================================================
452
+ /**
453
+ * Calculate compensation needed to keep an anchor's edge fixed when its height changes.
454
+ *
455
+ * With centerOrigin=true, when height increases the element grows equally up and down from center.
456
+ * The center stays fixed by CSS, so we need to move the element to keep the desired edge fixed.
457
+ *
458
+ * @param edge - Which edge should stay fixed ('top' or 'bottom')
459
+ * @param heightDelta - Change in height (positive = grew, negative = shrunk)
460
+ * @returns Compensation in pixels (add to current translateY)
461
+ *
462
+ * @example
463
+ * // If edge is 'bottom' and element grew by 20px:
464
+ * // Bottom edge moved DOWN by 10px, so move center UP (-10px) to keep bottom fixed
465
+ * calculateAnchorHeightCompensation('bottom', 20) // returns -10
466
+ */
467
+ function calculateAnchorHeightCompensation(edge, heightDelta) {
468
+ // If edge is 'bottom': bottom edge moves DOWN by heightDelta/2, move center UP to compensate
469
+ // If edge is 'top': top edge moves UP by heightDelta/2, move center DOWN to compensate
470
+ return edge === 'bottom' ? -heightDelta / 2 : heightDelta / 2;
471
+ }
472
+ /**
473
+ * Calculate compensation for target elements when anchor height changes.
474
+ *
475
+ * When anchor grows, its edge toward the target moves, plus the anchor itself moves.
476
+ * Target must move by the full height delta to maintain the gap.
477
+ *
478
+ * @param edge - Anchor's fixed edge ('top' or 'bottom')
479
+ * @param heightDelta - Change in anchor height (positive = grew, negative = shrunk)
480
+ * @returns Compensation in pixels (add to current translateY)
481
+ *
482
+ * @example
483
+ * // If anchor edge is 'bottom' and anchor grew by 20px:
484
+ * // Target (above anchor) must move UP by 20px to maintain gap
485
+ * calculateTargetCompensationForAnchorGrowth('bottom', 20) // returns -20
486
+ */
487
+ function calculateTargetCompensationForAnchorGrowth(edge, heightDelta) {
488
+ // If edge='bottom': anchor grows UP, target is above, target must move UP
489
+ // If edge='top': anchor grows DOWN, target is below, target must move DOWN
490
+ return edge === 'bottom' ? -heightDelta : heightDelta;
491
+ }
492
+ /**
493
+ * Calculate self-compensation for a target element when its own height changes.
494
+ *
495
+ * Target uses the same direction as anchor - it keeps the same edge fixed.
496
+ *
497
+ * @param edge - The fixed edge inherited from anchor ('top' or 'bottom')
498
+ * @param heightDelta - Change in target height (positive = grew, negative = shrunk)
499
+ * @returns Compensation in pixels (add to current translateY)
500
+ */
501
+ function calculateTargetSelfCompensation(edge, heightDelta) {
502
+ // Same logic as anchor - keep the same edge fixed
503
+ return edge === 'bottom' ? -heightDelta / 2 : heightDelta / 2;
504
+ }
505
+ /**
506
+ * Calculate compensation for subsequent elements when a target's height changes.
507
+ *
508
+ * Elements after the growing target need to move by the full height delta
509
+ * to maintain their gaps with the target.
510
+ *
511
+ * @param edge - The fixed edge inherited from anchor ('top' or 'bottom')
512
+ * @param heightDelta - Change in target height (positive = grew, negative = shrunk)
513
+ * @returns Compensation in pixels (add to current translateY)
514
+ */
515
+ function calculateSubsequentCompensation(edge, heightDelta) {
516
+ // Subsequent elements need to move by full heightDelta
517
+ return edge === 'bottom' ? -heightDelta : heightDelta;
518
+ }
519
+ /**
520
+ * Capture the initial configuration for edge-locking an anchor element.
521
+ *
522
+ * @param anchorRef - Reference to the anchor DOM element
523
+ * @param bannerContainerRef - Reference to the banner container
524
+ * @param sizeMultiplier - Current size multiplier for scaling
525
+ * @returns Configuration object for edge-locking, or null if refs are invalid
526
+ */
527
+ function captureAnchorEdgeConfig(anchorId, anchorRef, bannerContainerRef, sizeMultiplier) {
528
+ const edge = detectNearestEdge(anchorRef, bannerContainerRef, sizeMultiplier);
529
+ const gapToEdge = calculateGapToEdge(anchorRef, edge, bannerContainerRef, sizeMultiplier);
530
+ const initialHeight = anchorRef.getBoundingClientRect().height / sizeMultiplier;
531
+ return {
532
+ anchorId,
533
+ edge,
534
+ gapToEdge,
535
+ initialHeight,
536
+ };
537
+ }
538
+ /**
539
+ * Measure the heights of multiple elements.
540
+ *
541
+ * @param elementIds - Set of element IDs to measure
542
+ * @param refs - Object containing logo and copies refs
543
+ * @param copies - Array of copy configurations
544
+ * @param sizeMultiplier - Current size multiplier for scaling
545
+ * @returns Record mapping element ID to scaled height
546
+ */
547
+ function measureElementHeights(elementIds, refs, copies, sizeMultiplier) {
548
+ const heights = {};
549
+ elementIds.forEach(elementId => {
550
+ const ref = getElementRef(elementId, refs, copies);
551
+ if (ref) {
552
+ heights[elementId] = ref.getBoundingClientRect().height / sizeMultiplier;
553
+ }
554
+ });
555
+ return heights;
556
+ }
557
+ // ============================================================================
558
+ // Generic Utilities
559
+ // ============================================================================
560
+ /**
561
+ * Compare two Maps for equality.
562
+ *
563
+ * @param map1 - First map to compare
564
+ * @param map2 - Second map to compare
565
+ * @returns True if maps have same keys and values
566
+ *
567
+ * @example
568
+ * const map1 = new Map([['a', '1'], ['b', '2']]);
569
+ * const map2 = new Map([['a', '1'], ['b', '2']]);
570
+ * mapsAreEqual(map1, map2) // returns true
571
+ */
572
+ function mapsAreEqual(map1, map2) {
573
+ if (map1.size !== map2.size)
574
+ return false;
575
+ for (const [key, value] of map1) {
576
+ if (map2.get(key) !== value)
577
+ return false;
578
+ }
579
+ return true;
580
+ }
@@ -3,26 +3,14 @@
3
3
  * Based on maxLengthThreshold values used in font size calculations
4
4
  */
5
5
  export interface StyleCharacterLimits {
6
- copy1: number;
7
- copy2?: number;
6
+ limits: number[];
8
7
  copyCount: number;
9
8
  }
10
9
  export interface BannerConfig {
11
- copy1: {
10
+ copies: {
12
11
  supported: true;
13
- characterLimit: number;
14
- isOptional: boolean;
15
- };
16
- copy2?: {
17
- supported: boolean;
18
- characterLimit?: number;
19
- isOptional?: boolean;
20
- };
21
- fontSize_01: {
22
- supported: true;
23
- };
24
- fontSize_02?: {
25
- supported: boolean;
12
+ characterLimits: number[];
13
+ isOptional: boolean[];
26
14
  };
27
15
  logoUrl: {
28
16
  supported: true;
@@ -1 +1 @@
1
- {"version":3,"file":"characterLimits.d.ts","sourceRoot":"","sources":["../../src/constants/characterLimits.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;IACxE,KAAK,CAAC,EAAE;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9E,WAAW,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IACjC,WAAW,CAAC,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACrC,OAAO,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IAC7B,kBAAkB,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IACxC,0BAA0B,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IAChD,yBAAyB,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAClD,kBAAkB,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;CACzC;AAED,MAAM,WAAW,qBAAqB;IACpC,CAAC,WAAW,EAAE,MAAM,GAAG;QACrB,CAAC,cAAc,EAAE,MAAM,GAAG,oBAAoB,CAAC;KAChD,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,WAAW,EAAE,MAAM,GAAG;QACrB,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY,CAAC;KACxC,CAAC;CACH;AAED;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,EAAE,qBAqB1C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,EACnB,gBAAgB,MAAM,KACrB,oBAAoB,GAAG,IAEzB,CAAC;AA4BF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,eAyBnC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAC1B,aAAa,MAAM,EACnB,gBAAgB,MAAM,KACrB,YAAY,GAAG,IAEjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,GAAG,SAAS,EAAE,OAAO,MAAM,KAAG,OAItE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,MAAM,EAE3C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,aAAa,MAAM,KAAG,MAAM,EAIjE,CAAC"}
1
+ {"version":3,"file":"characterLimits.d.ts","sourceRoot":"","sources":["../../src/constants/characterLimits.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE;QACN,SAAS,EAAE,IAAI,CAAC;QAChB,eAAe,EAAE,MAAM,EAAE,CAAC;QAC1B,UAAU,EAAE,OAAO,EAAE,CAAC;KACvB,CAAC;IACF,OAAO,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IAC7B,kBAAkB,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IACxC,0BAA0B,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;IAChD,yBAAyB,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAClD,kBAAkB,EAAE;QAAE,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC;CACzC;AAED,MAAM,WAAW,qBAAqB;IACpC,CAAC,WAAW,EAAE,MAAM,GAAG;QACrB,CAAC,cAAc,EAAE,MAAM,GAAG,oBAAoB,CAAC;KAChD,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,WAAW,EAAE,MAAM,GAAG;QACrB,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY,CAAC;KACxC,CAAC;CACH;AAED;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,EAAE,qBAqB1C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,EACnB,gBAAgB,MAAM,KACrB,oBAAoB,GAAG,IAEzB,CAAC;AA8BF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,eAyBnC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAC1B,aAAa,MAAM,EACnB,gBAAgB,MAAM,KACrB,YAAY,GAAG,IAEjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,GAAG,SAAS,EAAE,OAAO,MAAM,KAAG,OAItE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,MAAM,EAE3C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,aAAa,MAAM,KAAG,MAAM,EAIjE,CAAC"}