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,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useHeightCompensation hook
|
|
4
|
+
*
|
|
5
|
+
* Handles height compensation for anchor and target elements when their text changes.
|
|
6
|
+
* Maintains edge-locking by adjusting positions when element heights change.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.useHeightCompensation = useHeightCompensation;
|
|
10
|
+
const react_1 = require("react");
|
|
11
|
+
const positioningUtils_1 = require("../../../styles/utils/positioningUtils");
|
|
12
|
+
/**
|
|
13
|
+
* Hook that manages height compensation for anchor and target elements.
|
|
14
|
+
*
|
|
15
|
+
* Responsibilities:
|
|
16
|
+
* - Adjust anchor position when its height changes (edge-locking)
|
|
17
|
+
* - Adjust target positions when anchor grows
|
|
18
|
+
* - Adjust target positions when they grow (self-compensation)
|
|
19
|
+
* - Move subsequent elements in chain when any element grows
|
|
20
|
+
*/
|
|
21
|
+
function useHeightCompensation({ anchorEdgeConfig, setAnchorEdgeConfig, targetHeights, setTargetHeights, activeLinks, hasActiveLinks, copies, sizeMultiplier, creationMode, logoRef, copyRefs, bannerContainerRef, derivedAutoConfig, config, lineGaps, onCopyPositionChange, }) {
|
|
22
|
+
// Memoize ANCHOR text to trigger effect when it changes
|
|
23
|
+
const anchorText = (0, react_1.useMemo)(() => {
|
|
24
|
+
if (!anchorEdgeConfig)
|
|
25
|
+
return '';
|
|
26
|
+
const { anchorId } = anchorEdgeConfig;
|
|
27
|
+
if (anchorId.startsWith('copy-')) {
|
|
28
|
+
const styleSlot = parseInt(anchorId.replace('copy-', ''), 10);
|
|
29
|
+
const copy = copies.find(c => c.styleSlot === styleSlot) || copies[styleSlot];
|
|
30
|
+
return (copy === null || copy === void 0 ? void 0 : copy.text) || '';
|
|
31
|
+
}
|
|
32
|
+
return '';
|
|
33
|
+
}, [anchorEdgeConfig, copies]);
|
|
34
|
+
// Adjust ANCHOR position when its height changes to maintain gap with edge
|
|
35
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
36
|
+
if (!anchorEdgeConfig || !bannerContainerRef.current || !hasActiveLinks) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const frameId = requestAnimationFrame(() => {
|
|
40
|
+
const { anchorId, edge, initialHeight } = anchorEdgeConfig;
|
|
41
|
+
const anchorRef = (0, positioningUtils_1.getElementRef)(anchorId, { logo: logoRef.current, copies: copyRefs.current }, copies);
|
|
42
|
+
if (!anchorRef) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const currentHeight = anchorRef.getBoundingClientRect().height / sizeMultiplier;
|
|
46
|
+
const heightDelta = currentHeight - initialHeight;
|
|
47
|
+
if (Math.abs(heightDelta) < 0.5) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Calculate compensations using utility functions
|
|
51
|
+
const anchorCompensation = (0, positioningUtils_1.calculateAnchorHeightCompensation)(edge, heightDelta);
|
|
52
|
+
const targetCompensation = (0, positioningUtils_1.calculateTargetCompensationForAnchorGrowth)(edge, heightDelta);
|
|
53
|
+
// Adjust ANCHOR position
|
|
54
|
+
if (anchorId.startsWith('copy-')) {
|
|
55
|
+
const styleSlot = parseInt(anchorId.replace('copy-', ''), 10);
|
|
56
|
+
const copyIndex = copies.findIndex(c => c.styleSlot === styleSlot);
|
|
57
|
+
const actualIndex = copyIndex !== -1 ? copyIndex : styleSlot;
|
|
58
|
+
if (actualIndex >= 0 && actualIndex < copies.length && onCopyPositionChange) {
|
|
59
|
+
const copy = copies[actualIndex];
|
|
60
|
+
const currentTranslateY = copy.translateY || 0;
|
|
61
|
+
const newTranslateY = currentTranslateY + anchorCompensation;
|
|
62
|
+
onCopyPositionChange(actualIndex, {
|
|
63
|
+
x: copy.translateX || 0,
|
|
64
|
+
y: newTranslateY,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Adjust all TARGET positions to maintain gap with anchor
|
|
69
|
+
Object.keys(targetHeights).forEach(targetId => {
|
|
70
|
+
if (targetId.startsWith('copy-') && onCopyPositionChange) {
|
|
71
|
+
const styleSlot = parseInt(targetId.replace('copy-', ''), 10);
|
|
72
|
+
const copyIndex = copies.findIndex(c => c.styleSlot === styleSlot);
|
|
73
|
+
const actualIndex = copyIndex !== -1 ? copyIndex : styleSlot;
|
|
74
|
+
if (actualIndex >= 0 && actualIndex < copies.length) {
|
|
75
|
+
const copy = copies[actualIndex];
|
|
76
|
+
const currentTranslateY = copy.translateY || 0;
|
|
77
|
+
const newTranslateY = currentTranslateY + targetCompensation;
|
|
78
|
+
onCopyPositionChange(actualIndex, {
|
|
79
|
+
x: copy.translateX || 0,
|
|
80
|
+
y: newTranslateY,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// Update the initial height in config so we track from new baseline
|
|
86
|
+
setAnchorEdgeConfig(prev => prev ? { ...prev, initialHeight: currentHeight } : null);
|
|
87
|
+
});
|
|
88
|
+
return () => cancelAnimationFrame(frameId);
|
|
89
|
+
}, [anchorEdgeConfig, anchorText, sizeMultiplier, creationMode, onCopyPositionChange, logoRef, copyRefs, copies, targetHeights, bannerContainerRef, hasActiveLinks, setAnchorEdgeConfig]);
|
|
90
|
+
// Memoize TARGET texts to trigger effect when they change
|
|
91
|
+
const targetTexts = (0, react_1.useMemo)(() => {
|
|
92
|
+
if (!anchorEdgeConfig || Object.keys(targetHeights).length === 0)
|
|
93
|
+
return '';
|
|
94
|
+
const texts = [];
|
|
95
|
+
Object.keys(targetHeights).forEach(targetId => {
|
|
96
|
+
if (targetId.startsWith('copy-')) {
|
|
97
|
+
const styleSlot = parseInt(targetId.replace('copy-', ''), 10);
|
|
98
|
+
const copy = copies.find(c => c.styleSlot === styleSlot) || copies[styleSlot];
|
|
99
|
+
if (copy) {
|
|
100
|
+
texts.push(`${targetId}:${copy.text}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return texts.join('|');
|
|
105
|
+
}, [anchorEdgeConfig, targetHeights, copies]);
|
|
106
|
+
// Adjust TARGET positions when their height changes
|
|
107
|
+
// TARGETs grow in the same direction as ANCHOR (inherit edge from anchor)
|
|
108
|
+
// Also move subsequent elements in the chain to maintain gaps
|
|
109
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
110
|
+
if (!anchorEdgeConfig || !bannerContainerRef.current || !hasActiveLinks || Object.keys(targetHeights).length === 0) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const frameId = requestAnimationFrame(() => {
|
|
114
|
+
const { edge } = anchorEdgeConfig;
|
|
115
|
+
let hasUpdates = false;
|
|
116
|
+
const newTargetHeights = { ...targetHeights };
|
|
117
|
+
// Build links array from activeLinks for chain traversal
|
|
118
|
+
const links = [];
|
|
119
|
+
activeLinks.forEach((toId, fromId) => {
|
|
120
|
+
var _a, _b, _c;
|
|
121
|
+
const configLink = (_a = derivedAutoConfig === null || derivedAutoConfig === void 0 ? void 0 : derivedAutoConfig.links) === null || _a === void 0 ? void 0 : _a.find(l => l.fromElement === fromId && l.toElement === toId);
|
|
122
|
+
const gapRem = (_c = (_b = lineGaps.get(`${fromId}->${toId}`)) !== null && _b !== void 0 ? _b : configLink === null || configLink === void 0 ? void 0 : configLink.gapRem) !== null && _c !== void 0 ? _c : config.gapRem;
|
|
123
|
+
links.push({ from: fromId, to: toId, gapRem });
|
|
124
|
+
});
|
|
125
|
+
Object.entries(targetHeights).forEach(([targetId, initialHeight]) => {
|
|
126
|
+
const targetRef = (0, positioningUtils_1.getElementRef)(targetId, { logo: logoRef.current, copies: copyRefs.current }, copies);
|
|
127
|
+
if (!targetRef)
|
|
128
|
+
return;
|
|
129
|
+
const currentHeight = targetRef.getBoundingClientRect().height / sizeMultiplier;
|
|
130
|
+
const heightDelta = currentHeight - initialHeight;
|
|
131
|
+
if (Math.abs(heightDelta) < 0.5)
|
|
132
|
+
return;
|
|
133
|
+
// Calculate compensations using utility functions
|
|
134
|
+
const selfCompensation = (0, positioningUtils_1.calculateTargetSelfCompensation)(edge, heightDelta);
|
|
135
|
+
const subsequentCompensation = (0, positioningUtils_1.calculateSubsequentCompensation)(edge, heightDelta);
|
|
136
|
+
// Adjust this target's position
|
|
137
|
+
if (targetId.startsWith('copy-') && onCopyPositionChange) {
|
|
138
|
+
const styleSlot = parseInt(targetId.replace('copy-', ''), 10);
|
|
139
|
+
const copyIndex = copies.findIndex(c => c.styleSlot === styleSlot);
|
|
140
|
+
const actualIndex = copyIndex !== -1 ? copyIndex : styleSlot;
|
|
141
|
+
if (actualIndex >= 0 && actualIndex < copies.length) {
|
|
142
|
+
const copy = copies[actualIndex];
|
|
143
|
+
const currentTranslateY = copy.translateY || 0;
|
|
144
|
+
const newTranslateY = currentTranslateY + selfCompensation;
|
|
145
|
+
onCopyPositionChange(actualIndex, {
|
|
146
|
+
x: copy.translateX || 0,
|
|
147
|
+
y: newTranslateY,
|
|
148
|
+
});
|
|
149
|
+
newTargetHeights[targetId] = currentHeight;
|
|
150
|
+
hasUpdates = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Move all subsequent elements in the chain
|
|
154
|
+
const subsequentElements = (0, positioningUtils_1.getSubsequentElementsInChain)(targetId, links);
|
|
155
|
+
subsequentElements.forEach(subsequentId => {
|
|
156
|
+
if (subsequentId.startsWith('copy-') && onCopyPositionChange) {
|
|
157
|
+
const styleSlot = parseInt(subsequentId.replace('copy-', ''), 10);
|
|
158
|
+
const copyIndex = copies.findIndex(c => c.styleSlot === styleSlot);
|
|
159
|
+
const actualIndex = copyIndex !== -1 ? copyIndex : styleSlot;
|
|
160
|
+
if (actualIndex >= 0 && actualIndex < copies.length) {
|
|
161
|
+
const copy = copies[actualIndex];
|
|
162
|
+
const currentTranslateY = copy.translateY || 0;
|
|
163
|
+
const newTranslateY = currentTranslateY + subsequentCompensation;
|
|
164
|
+
onCopyPositionChange(actualIndex, {
|
|
165
|
+
x: copy.translateX || 0,
|
|
166
|
+
y: newTranslateY,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
if (hasUpdates) {
|
|
173
|
+
setTargetHeights(newTargetHeights);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
return () => cancelAnimationFrame(frameId);
|
|
177
|
+
}, [anchorEdgeConfig, targetTexts, targetHeights, sizeMultiplier, creationMode, onCopyPositionChange, logoRef, copyRefs, copies, bannerContainerRef, activeLinks, hasActiveLinks, derivedAutoConfig, config.gapRem, lineGaps, setTargetHeights]);
|
|
178
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAutoPositioning hook
|
|
3
|
+
*
|
|
4
|
+
* Re-exports from the modular implementation.
|
|
5
|
+
* This file maintains backwards compatibility with existing imports.
|
|
6
|
+
*/
|
|
7
|
+
export { useAutoPositioning, type UseAutoPositioningParams, type UseAutoPositioningReturn, type AutoPositioningOverride, type SubstyleConfig, type AutoPositioningConfig, type AutoPositioningLink, type GeneratedAutoPositioningConfig, createDebugPositions, } from './useAutoPositioning/index';
|
|
8
|
+
//# sourceMappingURL=useAutoPositioning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAutoPositioning.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/hooks/useAutoPositioning.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,8BAA8B,EACnC,oBAAoB,GACrB,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useAutoPositioning hook
|
|
4
|
+
*
|
|
5
|
+
* Re-exports from the modular implementation.
|
|
6
|
+
* This file maintains backwards compatibility with existing imports.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.createDebugPositions = exports.useAutoPositioning = void 0;
|
|
10
|
+
var index_1 = require("./useAutoPositioning/index");
|
|
11
|
+
Object.defineProperty(exports, "useAutoPositioning", { enumerable: true, get: function () { return index_1.useAutoPositioning; } });
|
|
12
|
+
Object.defineProperty(exports, "createDebugPositions", { enumerable: true, get: function () { return index_1.createDebugPositions; } });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useDragSnap hook
|
|
3
|
+
* Handles snap positioning and alignment line calculations during drag operations
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { CopyConfig } from '../../../types';
|
|
7
|
+
import type { AlignmentLine } from '../utils';
|
|
8
|
+
export interface UseDragSnapParams {
|
|
9
|
+
logoRef: React.RefObject<HTMLDivElement | null>;
|
|
10
|
+
copyRefs: React.MutableRefObject<(HTMLDivElement | null)[]>;
|
|
11
|
+
bannerContainerRef: React.RefObject<HTMLDivElement | null>;
|
|
12
|
+
copies: CopyConfig[];
|
|
13
|
+
sizeMultiplier: number;
|
|
14
|
+
}
|
|
15
|
+
export interface UseDragSnapReturn {
|
|
16
|
+
handleRotationSnap: (angle: number) => number;
|
|
17
|
+
handlePositionSnap: (draggedBounds: DOMRect, position: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
}) => {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
};
|
|
24
|
+
calculateAlignments: (draggedElementId: string) => AlignmentLine[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Hook that provides snap positioning and alignment line calculations during drag.
|
|
28
|
+
*/
|
|
29
|
+
export declare function useDragSnap({ logoRef, copyRefs, bannerContainerRef, copies, sizeMultiplier, }: UseDragSnapParams): UseDragSnapReturn;
|
|
30
|
+
//# sourceMappingURL=useDragSnap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDragSnap.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/hooks/useDragSnap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAOjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,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;IAC3D,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,kBAAkB,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7G,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,aAAa,EAAE,CAAC;CACpE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,kBAAkB,EAClB,MAAM,EACN,cAAc,GACf,EAAE,iBAAiB,GAAG,iBAAiB,CA0FvC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useDragSnap hook
|
|
4
|
+
* Handles snap positioning and alignment line calculations during drag operations
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.useDragSnap = useDragSnap;
|
|
11
|
+
const react_1 = __importDefault(require("react"));
|
|
12
|
+
const utils_1 = require("../utils");
|
|
13
|
+
/**
|
|
14
|
+
* Hook that provides snap positioning and alignment line calculations during drag.
|
|
15
|
+
*/
|
|
16
|
+
function useDragSnap({ logoRef, copyRefs, bannerContainerRef, copies, sizeMultiplier, }) {
|
|
17
|
+
// Rotation snap - uses util function from snapUtils.ts
|
|
18
|
+
const handleRotationSnap = react_1.default.useCallback((angle) => (0, utils_1.snapRotation)(angle), []);
|
|
19
|
+
// Position snap function - uses util functions from snapUtils.ts
|
|
20
|
+
const handlePositionSnap = react_1.default.useCallback((draggedBounds, position) => {
|
|
21
|
+
if (!bannerContainerRef.current)
|
|
22
|
+
return position;
|
|
23
|
+
const bannerBounds = bannerContainerRef.current.getBoundingClientRect();
|
|
24
|
+
// Convert dragged bounds to relative
|
|
25
|
+
const draggedRelative = (0, utils_1.toRelativeBounds)(draggedBounds, bannerBounds, sizeMultiplier);
|
|
26
|
+
// Get all other elements' relative bounds
|
|
27
|
+
const allElements = [
|
|
28
|
+
{ id: 'logo', ref: logoRef.current },
|
|
29
|
+
...copies.map((copy, index) => ({
|
|
30
|
+
id: `copy-${copy.id}`,
|
|
31
|
+
ref: copyRefs.current[index],
|
|
32
|
+
})),
|
|
33
|
+
];
|
|
34
|
+
const otherBoundsArray = allElements
|
|
35
|
+
.filter(({ ref }) => ref !== null)
|
|
36
|
+
.map(({ ref }) => (0, utils_1.toRelativeBounds)(ref.getBoundingClientRect(), bannerBounds, sizeMultiplier));
|
|
37
|
+
// Calculate snap delta using util
|
|
38
|
+
const { deltaX, deltaY } = (0, utils_1.calculateSnapDelta)(draggedRelative, otherBoundsArray);
|
|
39
|
+
return {
|
|
40
|
+
x: position.x + deltaX,
|
|
41
|
+
y: position.y + deltaY,
|
|
42
|
+
};
|
|
43
|
+
}, [logoRef, copyRefs, bannerContainerRef, copies, sizeMultiplier]);
|
|
44
|
+
// Calculate alignment lines when dragging an element
|
|
45
|
+
const calculateAlignments = react_1.default.useCallback((draggedElementId) => {
|
|
46
|
+
if (!bannerContainerRef.current)
|
|
47
|
+
return [];
|
|
48
|
+
// Get dragged element ref
|
|
49
|
+
let draggedRef = null;
|
|
50
|
+
if (draggedElementId === 'logo') {
|
|
51
|
+
draggedRef = logoRef.current;
|
|
52
|
+
}
|
|
53
|
+
else if (draggedElementId.startsWith('copy-')) {
|
|
54
|
+
const copyId = draggedElementId.replace('copy-', '');
|
|
55
|
+
const copyIndex = copies.findIndex(c => c.id === copyId);
|
|
56
|
+
if (copyIndex !== -1) {
|
|
57
|
+
draggedRef = copyRefs.current[copyIndex];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!draggedRef)
|
|
61
|
+
return [];
|
|
62
|
+
const bannerBounds = bannerContainerRef.current.getBoundingClientRect();
|
|
63
|
+
const draggedBounds = draggedRef.getBoundingClientRect();
|
|
64
|
+
const draggedRelative = (0, utils_1.toRelativeBounds)(draggedBounds, bannerBounds, sizeMultiplier);
|
|
65
|
+
// Collect all other elements' relative bounds
|
|
66
|
+
const allElements = [
|
|
67
|
+
{ id: 'logo', ref: logoRef.current },
|
|
68
|
+
...copies.map((copy, index) => ({
|
|
69
|
+
id: `copy-${copy.id}`,
|
|
70
|
+
ref: copyRefs.current[index],
|
|
71
|
+
})),
|
|
72
|
+
];
|
|
73
|
+
const alignments = [];
|
|
74
|
+
allElements.forEach(({ id, ref }) => {
|
|
75
|
+
// Skip the dragged element itself
|
|
76
|
+
if (id === draggedElementId || !ref)
|
|
77
|
+
return;
|
|
78
|
+
const otherBounds = ref.getBoundingClientRect();
|
|
79
|
+
const otherRelative = (0, utils_1.toRelativeBounds)(otherBounds, bannerBounds, sizeMultiplier);
|
|
80
|
+
// Use the pure utility function to calculate alignment lines
|
|
81
|
+
alignments.push(...(0, utils_1.calculateAlignmentLinesBetween)(draggedRelative, otherRelative, 0.5));
|
|
82
|
+
});
|
|
83
|
+
return alignments;
|
|
84
|
+
}, [logoRef, copyRefs, bannerContainerRef, copies, sizeMultiplier]);
|
|
85
|
+
return {
|
|
86
|
+
handleRotationSnap,
|
|
87
|
+
handlePositionSnap,
|
|
88
|
+
calculateAlignments,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useElementRefs hook
|
|
3
|
+
* Foundation hook for element reference helpers and overlap/alignment checks
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { CopyConfig } from '../../../types';
|
|
7
|
+
export interface UseElementRefsParams {
|
|
8
|
+
logoRef: React.RefObject<HTMLDivElement | null>;
|
|
9
|
+
copyRefs: React.MutableRefObject<(HTMLDivElement | null)[]>;
|
|
10
|
+
copies: CopyConfig[];
|
|
11
|
+
}
|
|
12
|
+
export interface UseElementRefsReturn {
|
|
13
|
+
getElementRef: (elementId: string) => HTMLDivElement | null;
|
|
14
|
+
areElementsOverlapping: (elementId1: string, elementId2: string) => boolean;
|
|
15
|
+
areVerticallyAligned: (elementId1: string, elementId2: string) => boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Hook that provides element reference helpers and overlap/alignment checks.
|
|
19
|
+
* Supports both copy-{uuid} and copy-{N} (styleSlot) ID formats.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useElementRefs({ logoRef, copyRefs, copies, }: UseElementRefsParams): UseElementRefsReturn;
|
|
22
|
+
//# sourceMappingURL=useElementRefs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useElementRefs.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/hooks/useElementRefs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,MAAM,WAAW,oBAAoB;IACnC,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,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,cAAc,GAAG,IAAI,CAAC;IAC5D,sBAAsB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5E,oBAAoB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;CAC3E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE,oBAAoB,GAAG,oBAAoB,CAqD7C"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* useElementRefs hook
|
|
4
|
+
* Foundation hook for element reference helpers and overlap/alignment checks
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.useElementRefs = useElementRefs;
|
|
11
|
+
const react_1 = __importDefault(require("react"));
|
|
12
|
+
const utils_1 = require("../utils");
|
|
13
|
+
/**
|
|
14
|
+
* Hook that provides element reference helpers and overlap/alignment checks.
|
|
15
|
+
* Supports both copy-{uuid} and copy-{N} (styleSlot) ID formats.
|
|
16
|
+
*/
|
|
17
|
+
function useElementRefs({ logoRef, copyRefs, copies, }) {
|
|
18
|
+
// Helper: Get element ref by ID (supports both copy-{uuid} and copy-{N} formats)
|
|
19
|
+
const getElementRef = react_1.default.useCallback((elementId) => {
|
|
20
|
+
if (elementId === 'logo') {
|
|
21
|
+
return logoRef.current;
|
|
22
|
+
}
|
|
23
|
+
else if (elementId.startsWith('copy-')) {
|
|
24
|
+
const suffix = elementId.substring(5); // Remove 'copy-' prefix
|
|
25
|
+
// Check if it's copy-N format (styleSlot)
|
|
26
|
+
if (/^\d+$/.test(suffix)) {
|
|
27
|
+
const styleSlotIndex = parseInt(suffix, 10);
|
|
28
|
+
// Find copy by styleSlot first, then fallback to array index
|
|
29
|
+
const copy = copies.find(c => c.styleSlot === styleSlotIndex);
|
|
30
|
+
if (copy) {
|
|
31
|
+
const copyIndex = copies.indexOf(copy);
|
|
32
|
+
return copyRefs.current[copyIndex];
|
|
33
|
+
}
|
|
34
|
+
// Fallback to array index
|
|
35
|
+
if (styleSlotIndex < copies.length) {
|
|
36
|
+
return copyRefs.current[styleSlotIndex];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// It's a UUID format - find by id
|
|
41
|
+
const copyIndex = copies.findIndex(c => c.id === suffix);
|
|
42
|
+
if (copyIndex !== -1) {
|
|
43
|
+
return copyRefs.current[copyIndex];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}, [logoRef, copyRefs, copies]);
|
|
49
|
+
// Helper: Check if two elements are overlapping
|
|
50
|
+
const areElementsOverlapping = react_1.default.useCallback((elementId1, elementId2) => {
|
|
51
|
+
const ref1 = getElementRef(elementId1);
|
|
52
|
+
const ref2 = getElementRef(elementId2);
|
|
53
|
+
if (!ref1 || !ref2)
|
|
54
|
+
return false;
|
|
55
|
+
return (0, utils_1.checkElementsOverlapping)(ref1.getBoundingClientRect(), ref2.getBoundingClientRect());
|
|
56
|
+
}, [getElementRef]);
|
|
57
|
+
// Helper: Check if two elements are vertically aligned
|
|
58
|
+
const areVerticallyAligned = react_1.default.useCallback((elementId1, elementId2) => {
|
|
59
|
+
const ref1 = getElementRef(elementId1);
|
|
60
|
+
const ref2 = getElementRef(elementId2);
|
|
61
|
+
if (!ref1 || !ref2)
|
|
62
|
+
return false;
|
|
63
|
+
return (0, utils_1.checkVerticallyAligned)(ref1.getBoundingClientRect(), ref2.getBoundingClientRect());
|
|
64
|
+
}, [getElementRef]);
|
|
65
|
+
return {
|
|
66
|
+
getElementRef,
|
|
67
|
+
areElementsOverlapping,
|
|
68
|
+
areVerticallyAligned,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useLineDrawing hook
|
|
3
|
+
* Manages manual line drawing state and interactions for auto-positioning
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { CopyConfig } from '../../../types';
|
|
7
|
+
import type { AutoPositioningConfig } from '../../styles/types/substyleTypes';
|
|
8
|
+
export interface UseLineDrawingParams {
|
|
9
|
+
bannerContainerRef: React.RefObject<HTMLDivElement | null>;
|
|
10
|
+
copies: CopyConfig[];
|
|
11
|
+
sizeMultiplier: number;
|
|
12
|
+
creationMode: boolean;
|
|
13
|
+
areElementsOverlapping: (elementId1: string, elementId2: string) => boolean;
|
|
14
|
+
areVerticallyAligned: (elementId1: string, elementId2: string) => boolean;
|
|
15
|
+
/** Auto-positioning config from substyle - used to initialize completedLines in creationMode */
|
|
16
|
+
autoPositioningConfig?: AutoPositioningConfig;
|
|
17
|
+
/** Unique key identifying the current style/substyle configuration - triggers reset when changed */
|
|
18
|
+
configKey?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface UseLineDrawingReturn {
|
|
21
|
+
drawingFrom: string | null;
|
|
22
|
+
drawingMousePos: {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
} | null;
|
|
26
|
+
completedLines: Map<string, string>;
|
|
27
|
+
manualLines: Set<string>;
|
|
28
|
+
setCompletedLines: React.Dispatch<React.SetStateAction<Map<string, string>>>;
|
|
29
|
+
setManualLines: React.Dispatch<React.SetStateAction<Set<string>>>;
|
|
30
|
+
handleToggleAutoPositioning: (elementId: string) => void;
|
|
31
|
+
handleMouseMove: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
32
|
+
handleContainerClick: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
33
|
+
handleCompleteLineTo: (targetId: string) => void;
|
|
34
|
+
convertToStyleSlotId: (elementId: string) => string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Hook that manages line drawing state and interactions for manual auto-positioning links.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useLineDrawing({ bannerContainerRef, copies, sizeMultiplier, creationMode, areElementsOverlapping, areVerticallyAligned, autoPositioningConfig, configKey, }: UseLineDrawingParams): UseLineDrawingReturn;
|
|
40
|
+
//# sourceMappingURL=useLineDrawing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLineDrawing.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/hooks/useLineDrawing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAG9E,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC3D,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,sBAAsB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5E,oBAAoB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1E,gGAAgG;IAChG,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,oGAAoG;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,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,2BAA2B,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,eAAe,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAC/D,oBAAoB,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IACpE,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,kBAAkB,EAClB,MAAM,EACN,cAAc,EACd,YAAY,EACZ,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,GACV,EAAE,oBAAoB,GAAG,oBAAoB,CAkL7C"}
|