@littlecarlito/blorktools 0.50.4 → 0.51.0
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/bin/cli.js +69 -0
- package/package.json +13 -7
- package/src/asset_debugger/axis-indicator/axis-indicator.css +6 -0
- package/src/asset_debugger/axis-indicator/axis-indicator.html +20 -0
- package/src/asset_debugger/axis-indicator/axis-indicator.js +822 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.css +142 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.html +80 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.js +791 -0
- package/src/asset_debugger/header/header.css +73 -0
- package/src/asset_debugger/header/header.html +24 -0
- package/src/asset_debugger/header/header.js +224 -0
- package/src/asset_debugger/index.html +76 -0
- package/src/asset_debugger/landing-page/landing-page.css +396 -0
- package/src/asset_debugger/landing-page/landing-page.html +81 -0
- package/src/asset_debugger/landing-page/landing-page.js +611 -0
- package/src/asset_debugger/loading-splash/loading-splash.css +195 -0
- package/src/asset_debugger/loading-splash/loading-splash.html +22 -0
- package/src/asset_debugger/loading-splash/loading-splash.js +59 -0
- package/src/asset_debugger/loading-splash/preview-loading-splash.js +66 -0
- package/src/asset_debugger/main.css +14 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.css +41 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.html +18 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.js +111 -0
- package/src/asset_debugger/modals/examples-modal/examples.js +125 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.css +452 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.html +87 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.js +675 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.css +219 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.html +20 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.js +548 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.css +103 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.html +158 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.js +475 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.css +263 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.html +123 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.js +136 -0
- package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.css +94 -0
- package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.js +312 -0
- package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.css +129 -0
- package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.js +486 -0
- package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.css +545 -0
- package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.js +538 -0
- package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.css +70 -0
- package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.js +586 -0
- package/src/asset_debugger/panels/world-panel/world-panel.css +364 -0
- package/src/asset_debugger/panels/world-panel/world-panel.html +173 -0
- package/src/asset_debugger/panels/world-panel/world-panel.js +1891 -0
- package/src/asset_debugger/router.js +190 -0
- package/src/asset_debugger/util/animation/playback/animation-playback-controller.js +150 -0
- package/src/asset_debugger/util/animation/playback/animation-preview-controller.js +316 -0
- package/src/asset_debugger/util/animation/playback/css3d-bounce-controller.js +400 -0
- package/src/asset_debugger/util/animation/playback/css3d-reversal-controller.js +821 -0
- package/src/asset_debugger/util/animation/render/css3d-prerender-controller.js +696 -0
- package/src/asset_debugger/util/animation/render/debug-texture-factory.js +0 -0
- package/src/asset_debugger/util/animation/render/iframe2texture-render-controller.js +199 -0
- package/src/asset_debugger/util/animation/render/image2texture-prerender-controller.js +461 -0
- package/src/asset_debugger/util/animation/render/pbr-material-factory.js +82 -0
- package/src/asset_debugger/util/common.css +280 -0
- package/src/asset_debugger/util/data/animation-classifier.js +323 -0
- package/src/asset_debugger/util/data/duplicate-handler.js +20 -0
- package/src/asset_debugger/util/data/glb-buffer-manager.js +407 -0
- package/src/asset_debugger/util/data/glb-classifier.js +290 -0
- package/src/asset_debugger/util/data/html-formatter.js +76 -0
- package/src/asset_debugger/util/data/html-linter.js +276 -0
- package/src/asset_debugger/util/data/localstorage-manager.js +265 -0
- package/src/asset_debugger/util/data/mesh-html-manager.js +295 -0
- package/src/asset_debugger/util/data/string-serder.js +303 -0
- package/src/asset_debugger/util/data/texture-classifier.js +663 -0
- package/src/asset_debugger/util/data/upload/background-file-handler.js +292 -0
- package/src/asset_debugger/util/data/upload/dropzone-preview-controller.js +396 -0
- package/src/asset_debugger/util/data/upload/file-upload-manager.js +495 -0
- package/src/asset_debugger/util/data/upload/glb-file-handler.js +36 -0
- package/src/asset_debugger/util/data/upload/glb-preview-controller.js +317 -0
- package/src/asset_debugger/util/data/upload/lighting-file-handler.js +194 -0
- package/src/asset_debugger/util/data/upload/model-file-manager.js +104 -0
- package/src/asset_debugger/util/data/upload/texture-file-handler.js +166 -0
- package/src/asset_debugger/util/data/upload/zip-handler.js +686 -0
- package/src/asset_debugger/util/loaders/html2canvas-loader.js +107 -0
- package/src/asset_debugger/util/rig/bone-kinematics.js +403 -0
- package/src/asset_debugger/util/rig/rig-constraint-manager.js +618 -0
- package/src/asset_debugger/util/rig/rig-controller.js +612 -0
- package/src/asset_debugger/util/rig/rig-factory.js +628 -0
- package/src/asset_debugger/util/rig/rig-handle-factory.js +46 -0
- package/src/asset_debugger/util/rig/rig-label-factory.js +441 -0
- package/src/asset_debugger/util/rig/rig-mouse-handler.js +377 -0
- package/src/asset_debugger/util/rig/rig-state-manager.js +175 -0
- package/src/asset_debugger/util/rig/rig-tooltip-manager.js +267 -0
- package/src/asset_debugger/util/rig/rig-ui-factory.js +700 -0
- package/src/asset_debugger/util/scene/background-manager.js +284 -0
- package/src/asset_debugger/util/scene/camera-controller.js +243 -0
- package/src/asset_debugger/util/scene/css3d-debug-controller.js +406 -0
- package/src/asset_debugger/util/scene/css3d-frame-factory.js +113 -0
- package/src/asset_debugger/util/scene/css3d-scene-manager.js +529 -0
- package/src/asset_debugger/util/scene/glb-controller.js +208 -0
- package/src/asset_debugger/util/scene/lighting-manager.js +690 -0
- package/src/asset_debugger/util/scene/threejs-model-manager.js +437 -0
- package/src/asset_debugger/util/scene/threejs-preview-manager.js +207 -0
- package/src/asset_debugger/util/scene/threejs-preview-setup.js +478 -0
- package/src/asset_debugger/util/scene/threejs-scene-controller.js +286 -0
- package/src/asset_debugger/util/scene/ui-manager.js +107 -0
- package/src/asset_debugger/util/state/animation-state.js +128 -0
- package/src/asset_debugger/util/state/css3d-state.js +83 -0
- package/src/asset_debugger/util/state/glb-preview-state.js +31 -0
- package/src/asset_debugger/util/state/log-util.js +197 -0
- package/src/asset_debugger/util/state/scene-state.js +452 -0
- package/src/asset_debugger/util/state/threejs-state.js +54 -0
- package/src/asset_debugger/util/workers/lighting-worker.js +61 -0
- package/src/asset_debugger/util/workers/model-worker.js +109 -0
- package/src/asset_debugger/util/workers/texture-worker.js +54 -0
- package/src/asset_debugger/util/workers/worker-manager.js +212 -0
- package/src/asset_debugger/widgets/mesh-info-widget.js +280 -0
- package/src/index.html +261 -0
- package/src/index.js +8 -0
- package/vite.config.js +66 -0
|
@@ -0,0 +1,821 @@
|
|
|
1
|
+
import { animationStack, reverseAnimationFrameId, setReverseAnimationFrameId } from "../../state/css3d-state";
|
|
2
|
+
/**
|
|
3
|
+
* Pop and play the next animation from the stack in reverse
|
|
4
|
+
* @param {HTMLIFrameElement} iframe - The iframe containing animations
|
|
5
|
+
*/
|
|
6
|
+
export function playNextReverseAnimation(iframe) {
|
|
7
|
+
if (animationStack.length === 0) {
|
|
8
|
+
console.debug('No more animations to play in reverse');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Cancel any pending reverse animation
|
|
13
|
+
if (reverseAnimationFrameId) {
|
|
14
|
+
cancelAnimationFrame(reverseAnimationFrameId);
|
|
15
|
+
setReverseAnimationFrameId(null);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Pop the next animation from the stack
|
|
19
|
+
const nextItem = animationStack.pop();
|
|
20
|
+
|
|
21
|
+
// Check if this is a delay marker
|
|
22
|
+
if (nextItem.type === 'delay') {
|
|
23
|
+
console.debug(`Processing delay of ${nextItem.duration}ms`);
|
|
24
|
+
// For delays, wait the specified time before processing the next animation
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
playNextReverseAnimation(iframe);
|
|
27
|
+
}, nextItem.duration);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check if this is a batch of animations
|
|
32
|
+
if (nextItem.type === 'batch') {
|
|
33
|
+
console.debug(`Playing batch of ${nextItem.animations.length} animations in reverse`);
|
|
34
|
+
|
|
35
|
+
// Process each animation in the batch simultaneously
|
|
36
|
+
const animations = nextItem.animations;
|
|
37
|
+
let maxDuration = 0;
|
|
38
|
+
|
|
39
|
+
// First pass to find elements and calculate max duration
|
|
40
|
+
animations.forEach(animation => {
|
|
41
|
+
// Find the target element for this animation
|
|
42
|
+
const target = findTargetElement(iframe, animation);
|
|
43
|
+
animation._target = target; // Store the found target for use in the second pass
|
|
44
|
+
|
|
45
|
+
// Track the maximum duration in this batch
|
|
46
|
+
const duration = (animation.duration || 0.3) * 1000;
|
|
47
|
+
if (duration > maxDuration) {
|
|
48
|
+
maxDuration = duration;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Second pass to apply all animations simultaneously
|
|
53
|
+
animations.forEach(animation => {
|
|
54
|
+
const target = animation._target;
|
|
55
|
+
if (!target) {
|
|
56
|
+
console.debug(`No element found for animation: ${animation.name || 'unnamed'}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
// Apply the reverse animation based on type
|
|
62
|
+
if (animation.type === 'transition') {
|
|
63
|
+
applyReverseTransition(target, animation);
|
|
64
|
+
} else {
|
|
65
|
+
applyReverseAnimation(target, animation);
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
console.error('Error applying reverse animation in batch:', err);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Wait for the longest animation in the batch to complete before proceeding
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
playNextReverseAnimation(iframe);
|
|
75
|
+
}, maxDuration + 50); // Add small buffer
|
|
76
|
+
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// For backward compatibility - handle individual animation item
|
|
81
|
+
console.debug(`Playing individual animation in reverse: ${nextItem.name || 'unnamed'}`);
|
|
82
|
+
|
|
83
|
+
// Try multiple strategies to find the element
|
|
84
|
+
const target = findTargetElement(iframe, nextItem);
|
|
85
|
+
|
|
86
|
+
if (!target) {
|
|
87
|
+
console.debug(`No element found for animation: ${nextItem.name}`);
|
|
88
|
+
// Continue with the next animation after a short delay
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
playNextReverseAnimation(iframe);
|
|
91
|
+
}, 50);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Apply appropriate reversal based on animation type
|
|
96
|
+
try {
|
|
97
|
+
if (nextItem.type === 'transition') {
|
|
98
|
+
// Handle transitions using stored initial/target values
|
|
99
|
+
applyReverseTransition(target, nextItem);
|
|
100
|
+
} else {
|
|
101
|
+
// Handle CSS animations using more intelligent logic
|
|
102
|
+
applyReverseAnimation(target, nextItem);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Calculate when to play the next animation
|
|
106
|
+
const totalDuration = (nextItem.duration || 0.3) * 1000;
|
|
107
|
+
|
|
108
|
+
// After this animation completes, play the next one
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
playNextReverseAnimation(iframe);
|
|
111
|
+
}, totalDuration + 50); // Add a small buffer
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.error('Error applying reverse animation:', err);
|
|
114
|
+
// Continue with the next animation
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
playNextReverseAnimation(iframe);
|
|
117
|
+
}, 50);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Helper function to find the target element for an animation
|
|
123
|
+
* @param {HTMLIFrameElement} iframe - The iframe containing the document
|
|
124
|
+
* @param {Object} animation - The animation data
|
|
125
|
+
* @returns {Element|null} The found element or null
|
|
126
|
+
*/
|
|
127
|
+
function findTargetElement(iframe, animation) {
|
|
128
|
+
if (!iframe || !animation) return null;
|
|
129
|
+
|
|
130
|
+
let target = null;
|
|
131
|
+
try {
|
|
132
|
+
if (iframe.contentDocument) {
|
|
133
|
+
// Strategy 1: Try the stored selector
|
|
134
|
+
if (animation.selector) {
|
|
135
|
+
console.debug(`Finding element with selector: ${animation.selector}`);
|
|
136
|
+
try {
|
|
137
|
+
target = iframe.contentDocument.querySelector(animation.selector);
|
|
138
|
+
} catch (selectorErr) {
|
|
139
|
+
console.debug(`Invalid selector: ${animation.selector}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Strategy 2: Try by ID
|
|
144
|
+
if (!target && animation.elementId) {
|
|
145
|
+
console.debug(`Finding element by ID: ${animation.elementId}`);
|
|
146
|
+
target = iframe.contentDocument.getElementById(animation.elementId);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Strategy 3: Try by tag and class
|
|
150
|
+
if (!target && animation.elementTagName) {
|
|
151
|
+
console.debug(`Finding element by tag+class`);
|
|
152
|
+
const className = animation.elementClasses || '';
|
|
153
|
+
const tagName = animation.elementTagName.toLowerCase();
|
|
154
|
+
|
|
155
|
+
// If we have classes, try using them in the selector
|
|
156
|
+
if (className) {
|
|
157
|
+
try {
|
|
158
|
+
// Handle space-separated class names
|
|
159
|
+
const classes = className.split(' ').join('.');
|
|
160
|
+
const complexSelector = classes ? `${tagName}.${classes}` : tagName;
|
|
161
|
+
target = iframe.contentDocument.querySelector(complexSelector);
|
|
162
|
+
} catch (complexErr) {
|
|
163
|
+
console.debug(`Complex selector failed, trying tag name only`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// If still no target, try just by tag name
|
|
168
|
+
if (!target) {
|
|
169
|
+
const elements = iframe.contentDocument.getElementsByTagName(tagName);
|
|
170
|
+
if (elements.length > 0) {
|
|
171
|
+
target = elements[0];
|
|
172
|
+
console.debug(`Finding element by tag name: ${tagName}, found ${elements.length}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Strategy 4: For fadeIn/fadeOut elements - try a looser match by animation name
|
|
178
|
+
if (!target && animation.type === 'animation' &&
|
|
179
|
+
animation.name.toLowerCase().includes('fade')) {
|
|
180
|
+
console.debug(`Trying looser match for fade animation`);
|
|
181
|
+
|
|
182
|
+
// Try to find elements that might be visible
|
|
183
|
+
const possibleTargets = iframe.contentDocument.querySelectorAll('div, span, p');
|
|
184
|
+
for (const el of possibleTargets) {
|
|
185
|
+
// If it's visible, it could be our fade target
|
|
186
|
+
const style = window.getComputedStyle(el);
|
|
187
|
+
if (style.display !== 'none' && style.visibility !== 'hidden' &&
|
|
188
|
+
parseFloat(style.opacity) > 0) {
|
|
189
|
+
target = el;
|
|
190
|
+
console.debug(`Found possible fade target: ${el.tagName}`);
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Strategy 5: Check if this is an element that was removed and needs to be re-added
|
|
197
|
+
// Look for removed elements (especially for animations like fadeout, slideout, etc.)
|
|
198
|
+
if (!target) {
|
|
199
|
+
console.debug('This element may have been removed from the DOM, attempting to recreate it');
|
|
200
|
+
|
|
201
|
+
// For elements with a clear parent selector, try to recreate them
|
|
202
|
+
let parentElement = null;
|
|
203
|
+
|
|
204
|
+
// First try to find the parent from stored selectors
|
|
205
|
+
if (animation.parentSelector) {
|
|
206
|
+
parentElement = iframe.contentDocument.querySelector(animation.parentSelector);
|
|
207
|
+
} else if (animation.initialStyle && animation.initialStyle.parentSelector) {
|
|
208
|
+
parentElement = iframe.contentDocument.querySelector(animation.initialStyle.parentSelector);
|
|
209
|
+
} else if (animation.selector) {
|
|
210
|
+
// Try to extract a parent selector from the element's selector
|
|
211
|
+
const selectorParts = animation.selector.split('>');
|
|
212
|
+
if (selectorParts.length > 1) {
|
|
213
|
+
// Remove the last part (the element itself) and join the parent parts
|
|
214
|
+
const parentSelector = selectorParts.slice(0, -1).join('>').trim();
|
|
215
|
+
if (parentSelector) {
|
|
216
|
+
try {
|
|
217
|
+
parentElement = iframe.contentDocument.querySelector(parentSelector);
|
|
218
|
+
console.debug(`Found parent using selector part: ${parentSelector}`);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
console.debug(`Error finding parent with selector: ${parentSelector}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// If no specific parent found, try fallback to common containers
|
|
227
|
+
if (!parentElement) {
|
|
228
|
+
// For typing indicators, try to find the chat or typing container
|
|
229
|
+
if (animation.name.toLowerCase().includes('blink') ||
|
|
230
|
+
(animation.elementClasses && animation.elementClasses.includes('typing'))) {
|
|
231
|
+
// Look for typing container first
|
|
232
|
+
parentElement = iframe.contentDocument.querySelector('.typing');
|
|
233
|
+
|
|
234
|
+
// If no typing container, look for chat container
|
|
235
|
+
if (!parentElement) {
|
|
236
|
+
parentElement = iframe.contentDocument.querySelector('#chat, .chat, .messages, .conversation');
|
|
237
|
+
|
|
238
|
+
// If chat container found but no typing container, create typing container
|
|
239
|
+
if (parentElement && !iframe.contentDocument.querySelector('.typing')) {
|
|
240
|
+
const typingDiv = iframe.contentDocument.createElement('div');
|
|
241
|
+
typingDiv.className = 'typing';
|
|
242
|
+
parentElement.appendChild(typingDiv);
|
|
243
|
+
parentElement = typingDiv;
|
|
244
|
+
console.debug('Created new typing container in chat');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// If we found a parent element, try to recreate the missing element
|
|
251
|
+
if (parentElement) {
|
|
252
|
+
console.debug(`Found parent element ${parentElement.tagName}, recreating removed element`);
|
|
253
|
+
|
|
254
|
+
// Create a new element of the right type
|
|
255
|
+
const newElement = iframe.contentDocument.createElement(
|
|
256
|
+
animation.elementTagName || 'div'
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
// Add any classes it had
|
|
260
|
+
if (animation.elementClasses) {
|
|
261
|
+
newElement.className = animation.elementClasses;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Add ID if it had one
|
|
265
|
+
if (animation.elementId) {
|
|
266
|
+
newElement.id = animation.elementId;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Handle special case for blink animations (like typing indicators)
|
|
270
|
+
if (animation.name.toLowerCase().includes('blink')) {
|
|
271
|
+
// For blink animations, set initial styles and content
|
|
272
|
+
newElement.style.opacity = '0';
|
|
273
|
+
|
|
274
|
+
// If it's a typing indicator dot, add the dot content
|
|
275
|
+
if (animation.selector && animation.selector.includes('span')) {
|
|
276
|
+
newElement.textContent = '•';
|
|
277
|
+
console.debug('Added typing indicator dot content');
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
// For other animations, start with initial display state
|
|
281
|
+
newElement.style.display = 'none';
|
|
282
|
+
newElement.style.opacity = '0';
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Try to position the element correctly in the parent
|
|
286
|
+
// Check the selector to determine position
|
|
287
|
+
let position = 0;
|
|
288
|
+
if (animation.selector) {
|
|
289
|
+
// Extract nth-child information if available
|
|
290
|
+
const nthChildMatch = animation.selector.match(/:nth-child\((\d+)\)/);
|
|
291
|
+
if (nthChildMatch && nthChildMatch[1]) {
|
|
292
|
+
position = parseInt(nthChildMatch[1]) - 1;
|
|
293
|
+
console.debug(`Found position from selector: ${position}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Insert at the right position if possible
|
|
298
|
+
if (position > 0 && position < parentElement.children.length) {
|
|
299
|
+
parentElement.insertBefore(newElement, parentElement.children[position]);
|
|
300
|
+
console.debug(`Inserted element at position ${position}`);
|
|
301
|
+
} else {
|
|
302
|
+
// Otherwise append to the end
|
|
303
|
+
parentElement.appendChild(newElement);
|
|
304
|
+
console.debug(`Appended element to parent`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Use this as our target
|
|
308
|
+
target = newElement;
|
|
309
|
+
|
|
310
|
+
console.debug(`Created new element to replace removed one: ${animation.elementTagName || 'div'}`);
|
|
311
|
+
} else {
|
|
312
|
+
console.debug('Could not find parent element, cannot recreate removed element');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (err) {
|
|
317
|
+
console.error('Error finding element:', err);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return target;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Apply a reverse CSS animation intelligently
|
|
325
|
+
* @param {Element} target - The target element
|
|
326
|
+
* @param {Object} animation - The animation data
|
|
327
|
+
*/
|
|
328
|
+
function applyReverseAnimation(target, animation) {
|
|
329
|
+
if (!target || !animation) return;
|
|
330
|
+
|
|
331
|
+
console.debug(`Found element for animation: ${animation.name}`);
|
|
332
|
+
|
|
333
|
+
const classified = animation.classified || {};
|
|
334
|
+
const initialStyle = animation.initialStyle || {};
|
|
335
|
+
const finalStyle = animation.finalStyle || {};
|
|
336
|
+
|
|
337
|
+
// Use the animation's own duration or default to 0.3s
|
|
338
|
+
const duration = animation.duration || 0.3;
|
|
339
|
+
const timing = animation.timingFunction || 'ease';
|
|
340
|
+
|
|
341
|
+
// Special handling for blink animations (typing indicators)
|
|
342
|
+
if (animation.name.toLowerCase().includes('blink')) {
|
|
343
|
+
console.debug(`Applying reverse for blink animation`);
|
|
344
|
+
|
|
345
|
+
// Show the element immediately since these are usually dots that blink
|
|
346
|
+
target.style.animation = 'none';
|
|
347
|
+
target.style.transition = 'none';
|
|
348
|
+
target.style.opacity = '1';
|
|
349
|
+
target.style.visibility = 'visible';
|
|
350
|
+
target.style.display = 'inline-block';
|
|
351
|
+
|
|
352
|
+
// If this element is part of a typing indicator, ensure other elements are visible too
|
|
353
|
+
const parent = target.parentElement;
|
|
354
|
+
if (parent && parent.classList.contains('typing')) {
|
|
355
|
+
parent.style.display = 'block';
|
|
356
|
+
parent.style.visibility = 'visible';
|
|
357
|
+
parent.style.opacity = '1';
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Apply the blink animation in reverse
|
|
361
|
+
void target.offsetWidth; // Force reflow
|
|
362
|
+
target.style.animation = `${animation.name} ${duration}s ${timing} infinite`;
|
|
363
|
+
|
|
364
|
+
// Set a timeout to fade out the typing indicator when we're done with this animation
|
|
365
|
+
setTimeout(() => {
|
|
366
|
+
// Find all the spans in the typing container
|
|
367
|
+
const parent = target.parentElement;
|
|
368
|
+
if (parent) {
|
|
369
|
+
parent.style.transition = `opacity ${duration}s ${timing}`;
|
|
370
|
+
parent.style.opacity = '0';
|
|
371
|
+
|
|
372
|
+
setTimeout(() => {
|
|
373
|
+
parent.style.display = 'none';
|
|
374
|
+
}, duration * 1000);
|
|
375
|
+
}
|
|
376
|
+
}, duration * 1000 * 3); // Show for longer (3x duration) to make it visible
|
|
377
|
+
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Special handling for fades - they need opposite animations
|
|
382
|
+
else if (classified.category === 'fade') {
|
|
383
|
+
if (classified.isFadeIn) {
|
|
384
|
+
// Fade in -> Fade out
|
|
385
|
+
console.debug(`Applying fadeOut for fadeIn animation`);
|
|
386
|
+
|
|
387
|
+
// Stop any existing animations
|
|
388
|
+
target.style.animation = 'none';
|
|
389
|
+
target.style.transition = 'none';
|
|
390
|
+
|
|
391
|
+
// Force reflow
|
|
392
|
+
void target.offsetWidth;
|
|
393
|
+
|
|
394
|
+
// Apply immediate styles without animation first to ensure visibility
|
|
395
|
+
target.style.opacity = '1';
|
|
396
|
+
target.style.visibility = 'visible';
|
|
397
|
+
target.style.display = finalStyle.display || 'block';
|
|
398
|
+
|
|
399
|
+
// Force reflow again
|
|
400
|
+
void target.offsetWidth;
|
|
401
|
+
|
|
402
|
+
// Now set up the fade out transition
|
|
403
|
+
target.style.transition = `opacity ${duration}s ${timing}`;
|
|
404
|
+
|
|
405
|
+
// Use requestAnimationFrame to ensure the browser has time to apply the initial state
|
|
406
|
+
requestAnimationFrame(() => {
|
|
407
|
+
// Set opacity to 0 for fade out
|
|
408
|
+
target.style.opacity = '0';
|
|
409
|
+
|
|
410
|
+
// Set a callback to handle cleanup after the animation
|
|
411
|
+
setTimeout(() => {
|
|
412
|
+
// If the element was originally hidden, restore that state
|
|
413
|
+
if (initialStyle.opacity === '0' || parseFloat(initialStyle.opacity) < 0.1 ||
|
|
414
|
+
initialStyle.visibility === 'hidden' || initialStyle.display === 'none') {
|
|
415
|
+
target.style.visibility = 'hidden';
|
|
416
|
+
target.style.display = 'none';
|
|
417
|
+
}
|
|
418
|
+
}, duration * 1000);
|
|
419
|
+
});
|
|
420
|
+
} else {
|
|
421
|
+
// Fade out -> Fade in
|
|
422
|
+
console.debug(`Applying fadeIn for fadeOut animation`);
|
|
423
|
+
|
|
424
|
+
// Stop any existing animations
|
|
425
|
+
target.style.animation = 'none';
|
|
426
|
+
target.style.transition = 'none';
|
|
427
|
+
|
|
428
|
+
// First check if the element should actually be visible
|
|
429
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
430
|
+
console.debug('Element was originally hidden, keeping it hidden');
|
|
431
|
+
|
|
432
|
+
// Simply ensure the element is hidden
|
|
433
|
+
target.style.opacity = '0';
|
|
434
|
+
target.style.visibility = 'hidden';
|
|
435
|
+
target.style.display = 'none';
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Apply immediate styles without animation first
|
|
440
|
+
target.style.opacity = '0';
|
|
441
|
+
target.style.visibility = 'visible';
|
|
442
|
+
target.style.display = initialStyle.display || 'block';
|
|
443
|
+
|
|
444
|
+
// Force reflow
|
|
445
|
+
void target.offsetWidth;
|
|
446
|
+
|
|
447
|
+
// Now set up the fade in transition
|
|
448
|
+
target.style.transition = `opacity ${duration}s ${timing}`;
|
|
449
|
+
|
|
450
|
+
// Use requestAnimationFrame to ensure the browser has time to apply the initial state
|
|
451
|
+
requestAnimationFrame(() => {
|
|
452
|
+
// Set opacity to 1 for fade in
|
|
453
|
+
target.style.opacity = '1';
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Special handling for slides
|
|
458
|
+
else if (classified.category === 'slide') {
|
|
459
|
+
if (classified.isSlideIn) {
|
|
460
|
+
// Slide in -> Slide out
|
|
461
|
+
console.debug(`Applying slideOut for slideIn animation`);
|
|
462
|
+
|
|
463
|
+
// Clear existing animations
|
|
464
|
+
target.style.animation = 'none';
|
|
465
|
+
target.style.transition = 'none';
|
|
466
|
+
|
|
467
|
+
// Force reflow
|
|
468
|
+
void target.offsetWidth;
|
|
469
|
+
|
|
470
|
+
// Make sure element is visible first
|
|
471
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
472
|
+
target.style.visibility = 'visible';
|
|
473
|
+
target.style.display = 'block';
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Use an opposite animation
|
|
477
|
+
const oppositeAnim = getOppositeAnimation(animation.name, classified);
|
|
478
|
+
target.style.animation = `${oppositeAnim} ${duration}s ${timing} forwards`;
|
|
479
|
+
|
|
480
|
+
// Hide the element after animation is complete if it was originally hidden
|
|
481
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
482
|
+
setTimeout(() => {
|
|
483
|
+
target.style.visibility = 'hidden';
|
|
484
|
+
target.style.display = 'none';
|
|
485
|
+
}, duration * 1000);
|
|
486
|
+
}
|
|
487
|
+
} else {
|
|
488
|
+
// Slide out -> Slide in
|
|
489
|
+
console.debug(`Applying slideIn for slideOut animation`);
|
|
490
|
+
|
|
491
|
+
// Check if element should be visible in its original state
|
|
492
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
493
|
+
console.debug('Element was originally hidden, keeping it hidden');
|
|
494
|
+
target.style.visibility = 'hidden';
|
|
495
|
+
target.style.display = 'none';
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Clear existing animations
|
|
500
|
+
target.style.animation = 'none';
|
|
501
|
+
target.style.transition = 'none';
|
|
502
|
+
|
|
503
|
+
// Force reflow
|
|
504
|
+
void target.offsetWidth;
|
|
505
|
+
|
|
506
|
+
// Ensure the element is visible
|
|
507
|
+
target.style.visibility = 'visible';
|
|
508
|
+
target.style.display = initialStyle.display || 'block';
|
|
509
|
+
|
|
510
|
+
// Use an opposite animation
|
|
511
|
+
const oppositeAnim = getOppositeAnimation(animation.name, classified);
|
|
512
|
+
target.style.animation = `${oppositeAnim} ${duration}s ${timing} forwards`;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
// Special handling for zoom
|
|
516
|
+
else if (classified.category === 'zoom') {
|
|
517
|
+
if (classified.isZoomIn) {
|
|
518
|
+
// Zoom in -> Zoom out
|
|
519
|
+
console.debug(`Applying zoomOut for zoomIn animation`);
|
|
520
|
+
|
|
521
|
+
// Clear existing animations
|
|
522
|
+
target.style.animation = 'none';
|
|
523
|
+
target.style.transition = 'none';
|
|
524
|
+
|
|
525
|
+
// Force reflow
|
|
526
|
+
void target.offsetWidth;
|
|
527
|
+
|
|
528
|
+
// Make sure element is visible first
|
|
529
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
530
|
+
target.style.visibility = 'visible';
|
|
531
|
+
target.style.display = 'block';
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Use an opposite animation
|
|
535
|
+
const oppositeAnim = getOppositeAnimation(animation.name, classified);
|
|
536
|
+
target.style.animation = `${oppositeAnim} ${duration}s ${timing} forwards`;
|
|
537
|
+
|
|
538
|
+
// Hide the element after animation is complete if it was originally hidden
|
|
539
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
540
|
+
setTimeout(() => {
|
|
541
|
+
target.style.visibility = 'hidden';
|
|
542
|
+
target.style.display = 'none';
|
|
543
|
+
}, duration * 1000);
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
// Zoom out -> Zoom in
|
|
547
|
+
console.debug(`Applying zoomIn for zoomOut animation`);
|
|
548
|
+
|
|
549
|
+
// Check if element should be visible in its original state
|
|
550
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
551
|
+
console.debug('Element was originally hidden, keeping it hidden');
|
|
552
|
+
target.style.visibility = 'hidden';
|
|
553
|
+
target.style.display = 'none';
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Clear existing animations
|
|
558
|
+
target.style.animation = 'none';
|
|
559
|
+
target.style.transition = 'none';
|
|
560
|
+
|
|
561
|
+
// Force reflow
|
|
562
|
+
void target.offsetWidth;
|
|
563
|
+
|
|
564
|
+
// Ensure element is visible
|
|
565
|
+
target.style.visibility = 'visible';
|
|
566
|
+
target.style.display = initialStyle.display || 'block';
|
|
567
|
+
|
|
568
|
+
// Use an opposite animation
|
|
569
|
+
const oppositeAnim = getOppositeAnimation(animation.name, classified);
|
|
570
|
+
target.style.animation = `${oppositeAnim} ${duration}s ${timing} forwards`;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
// For other animations, apply a standard reverse
|
|
574
|
+
else {
|
|
575
|
+
// Standard reverse animation
|
|
576
|
+
console.debug(`Applying reverse animation: ${animation.name}`);
|
|
577
|
+
|
|
578
|
+
// Clear existing animations
|
|
579
|
+
target.style.animation = 'none';
|
|
580
|
+
target.style.transition = 'none';
|
|
581
|
+
|
|
582
|
+
// Handle visibility based on initial state
|
|
583
|
+
if (initialStyle.display === 'none' || initialStyle.visibility === 'hidden') {
|
|
584
|
+
// If the element was originally hidden, restore that state
|
|
585
|
+
target.style.visibility = 'hidden';
|
|
586
|
+
target.style.display = 'none';
|
|
587
|
+
} else {
|
|
588
|
+
// Ensure element is visible for the animation
|
|
589
|
+
target.style.visibility = 'visible';
|
|
590
|
+
target.style.display = initialStyle.display || 'block';
|
|
591
|
+
|
|
592
|
+
// Force reflow
|
|
593
|
+
void target.offsetWidth;
|
|
594
|
+
|
|
595
|
+
// Apply the reverse animation
|
|
596
|
+
target.style.animation = `${animation.name} ${duration}s ${timing} reverse forwards`;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Force a reflow to ensure the animation runs
|
|
601
|
+
void target.offsetWidth;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Create opposite animation for an animation property
|
|
606
|
+
* @param {string} animationName - Original animation name
|
|
607
|
+
* @param {Object} classification - Animation classification
|
|
608
|
+
* @returns {string} Opposite animation name
|
|
609
|
+
*/
|
|
610
|
+
function getOppositeAnimation(animationName, classification) {
|
|
611
|
+
if (!animationName) return '';
|
|
612
|
+
|
|
613
|
+
// If we have a valid classification, use it
|
|
614
|
+
if (classification) {
|
|
615
|
+
if (classification.isFadeIn) return animationName.replace(/fadein|fade-in|fade-in/i, 'fadeout');
|
|
616
|
+
if (classification.isFadeOut) return animationName.replace(/fadeout|fade-out|fade-out/i, 'fadein');
|
|
617
|
+
if (classification.isSlideIn) return animationName.replace(/slidein|slide-in|slide-in/i, 'slideout');
|
|
618
|
+
if (classification.isSlideOut) return animationName.replace(/slideout|slide-out|slide-out/i, 'slidein');
|
|
619
|
+
if (classification.isZoomIn) return animationName.replace(/zoomin|zoom-in|zoom-in/i, 'zoomout');
|
|
620
|
+
if (classification.isZoomOut) return animationName.replace(/zoomout|zoom-out|zoom-out/i, 'zoomin');
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const name = animationName.toLowerCase();
|
|
624
|
+
|
|
625
|
+
// Common animation pairs
|
|
626
|
+
const pairs = {
|
|
627
|
+
'fadein': 'fadeout',
|
|
628
|
+
'fade-in': 'fade-out',
|
|
629
|
+
'fadeout': 'fadein',
|
|
630
|
+
'fade-out': 'fade-in',
|
|
631
|
+
'slidein': 'slideout',
|
|
632
|
+
'slide-in': 'slide-out',
|
|
633
|
+
'slideout': 'slidein',
|
|
634
|
+
'slide-out': 'slide-in',
|
|
635
|
+
'zoomin': 'zoomout',
|
|
636
|
+
'zoom-in': 'zoom-out',
|
|
637
|
+
'zoomout': 'zoomin',
|
|
638
|
+
'zoom-out': 'zoom-in',
|
|
639
|
+
'rotatein': 'rotateout',
|
|
640
|
+
'rotate-in': 'rotate-out',
|
|
641
|
+
'rotateout': 'rotatein',
|
|
642
|
+
'rotate-out': 'rotate-in',
|
|
643
|
+
'scalein': 'scaleout',
|
|
644
|
+
'scale-in': 'scale-out',
|
|
645
|
+
'scaleout': 'scalein',
|
|
646
|
+
'scale-out': 'scale-in',
|
|
647
|
+
'expand': 'collapse',
|
|
648
|
+
'collapse': 'expand',
|
|
649
|
+
'show': 'hide',
|
|
650
|
+
'hide': 'show',
|
|
651
|
+
'open': 'close',
|
|
652
|
+
'close': 'open'
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// Check for each pattern in the animation name
|
|
656
|
+
for (const [pattern, opposite] of Object.entries(pairs)) {
|
|
657
|
+
if (name.includes(pattern)) {
|
|
658
|
+
// Replace the pattern with its opposite
|
|
659
|
+
return animationName.replace(new RegExp(pattern, 'i'), opposite);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// If no specific pattern is found, just use reverse
|
|
664
|
+
return animationName;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Apply a reverse transition intelligently
|
|
669
|
+
* @param {Element} target - The target element
|
|
670
|
+
* @param {Object} transition - The transition data
|
|
671
|
+
*/
|
|
672
|
+
function applyReverseTransition(target, transition) {
|
|
673
|
+
if (!target || !transition) return;
|
|
674
|
+
|
|
675
|
+
console.debug(`Applying reverse transition for: ${transition.property}`);
|
|
676
|
+
|
|
677
|
+
const classified = transition.classified || {};
|
|
678
|
+
const property = transition.property;
|
|
679
|
+
const duration = transition.duration || 0.3;
|
|
680
|
+
const timing = transition.timingFunction || 'ease';
|
|
681
|
+
const initialValue = transition.initialValue || null;
|
|
682
|
+
const finalValue = transition.finalValue || null;
|
|
683
|
+
const initialStyle = transition.initialStyle || {};
|
|
684
|
+
|
|
685
|
+
if (!property) {
|
|
686
|
+
console.debug('No property defined for transition');
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// First, remove any existing transitions
|
|
691
|
+
target.style.transition = 'none';
|
|
692
|
+
|
|
693
|
+
// Force a reflow to ensure previous transitions are cleared
|
|
694
|
+
void target.offsetWidth;
|
|
695
|
+
|
|
696
|
+
// Set up the new transition
|
|
697
|
+
if (property === 'opacity') {
|
|
698
|
+
// For opacity transitions, handle them specially to ensure visibility
|
|
699
|
+
const currentOpacity = window.getComputedStyle(target).opacity;
|
|
700
|
+
const targetOpacity = initialValue !== null ? initialValue :
|
|
701
|
+
(classified.isFadeIn ? '0' : '1');
|
|
702
|
+
|
|
703
|
+
// Check if the element should be visible in its original state
|
|
704
|
+
const wasOriginallyHidden = initialStyle.display === 'none' ||
|
|
705
|
+
initialStyle.visibility === 'hidden' ||
|
|
706
|
+
parseFloat(initialStyle.opacity) < 0.1;
|
|
707
|
+
|
|
708
|
+
if (parseFloat(currentOpacity) > 0 && parseFloat(targetOpacity) === 0) {
|
|
709
|
+
// Currently visible, going to fade out
|
|
710
|
+
target.style.transition = 'none';
|
|
711
|
+
target.style.visibility = 'visible';
|
|
712
|
+
target.style.opacity = '1';
|
|
713
|
+
|
|
714
|
+
// Force reflow
|
|
715
|
+
void target.offsetWidth;
|
|
716
|
+
|
|
717
|
+
// Now set up the transition
|
|
718
|
+
target.style.transition = `opacity ${duration}s ${timing}`;
|
|
719
|
+
|
|
720
|
+
// Apply the new opacity value using requestAnimationFrame
|
|
721
|
+
requestAnimationFrame(() => {
|
|
722
|
+
target.style.opacity = targetOpacity;
|
|
723
|
+
|
|
724
|
+
// Once fade out is complete, update visibility based on original state
|
|
725
|
+
setTimeout(() => {
|
|
726
|
+
if (wasOriginallyHidden) {
|
|
727
|
+
target.style.visibility = 'hidden';
|
|
728
|
+
target.style.display = 'none';
|
|
729
|
+
}
|
|
730
|
+
}, duration * 1000);
|
|
731
|
+
});
|
|
732
|
+
} else if (parseFloat(currentOpacity) < 0.1) {
|
|
733
|
+
// Currently invisible, but should it fade in?
|
|
734
|
+
if (wasOriginallyHidden) {
|
|
735
|
+
// It was originally hidden, so keep it hidden
|
|
736
|
+
console.debug('Element was originally hidden, keeping it hidden');
|
|
737
|
+
target.style.opacity = '0';
|
|
738
|
+
target.style.visibility = 'hidden';
|
|
739
|
+
target.style.display = 'none';
|
|
740
|
+
} else {
|
|
741
|
+
// It was originally visible, so fade it in
|
|
742
|
+
target.style.transition = 'none';
|
|
743
|
+
target.style.visibility = 'visible';
|
|
744
|
+
target.style.display = 'block';
|
|
745
|
+
target.style.opacity = '0';
|
|
746
|
+
|
|
747
|
+
// Force reflow
|
|
748
|
+
void target.offsetWidth;
|
|
749
|
+
|
|
750
|
+
// Set up transition
|
|
751
|
+
target.style.transition = `opacity ${duration}s ${timing}`;
|
|
752
|
+
|
|
753
|
+
// Apply the new opacity value using requestAnimationFrame
|
|
754
|
+
requestAnimationFrame(() => {
|
|
755
|
+
target.style.opacity = targetOpacity;
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
} else {
|
|
759
|
+
// Regular opacity transition
|
|
760
|
+
target.style.transition = `opacity ${duration}s ${timing}`;
|
|
761
|
+
// Force reflow
|
|
762
|
+
void target.offsetWidth;
|
|
763
|
+
// Apply the opacity value
|
|
764
|
+
target.style.opacity = targetOpacity;
|
|
765
|
+
}
|
|
766
|
+
} else {
|
|
767
|
+
// For non-opacity transitions, use a simpler approach
|
|
768
|
+
target.style.transition = `${property} ${duration}s ${timing}`;
|
|
769
|
+
|
|
770
|
+
// Force a reflow
|
|
771
|
+
void target.offsetWidth;
|
|
772
|
+
|
|
773
|
+
// For transitions, we want to go back to the initial value
|
|
774
|
+
if (initialValue) {
|
|
775
|
+
// If we have a valid initial value, use it
|
|
776
|
+
console.debug(`Reversing ${property} to initial value: ${initialValue}`);
|
|
777
|
+
requestAnimationFrame(() => {
|
|
778
|
+
target.style[property] = initialValue;
|
|
779
|
+
});
|
|
780
|
+
} else {
|
|
781
|
+
// Handle based on the property type
|
|
782
|
+
switch (classified.category) {
|
|
783
|
+
case 'move':
|
|
784
|
+
// Move transitions typically use position properties
|
|
785
|
+
requestAnimationFrame(() => {
|
|
786
|
+
target.style[property] = '0';
|
|
787
|
+
});
|
|
788
|
+
break;
|
|
789
|
+
|
|
790
|
+
case 'size':
|
|
791
|
+
if (classified.isExpand) {
|
|
792
|
+
// Was expanding, now shrink
|
|
793
|
+
requestAnimationFrame(() => {
|
|
794
|
+
target.style[property] = '0';
|
|
795
|
+
});
|
|
796
|
+
} else {
|
|
797
|
+
// Was shrinking, now expand
|
|
798
|
+
requestAnimationFrame(() => {
|
|
799
|
+
target.style[property] = 'auto';
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
break;
|
|
803
|
+
|
|
804
|
+
case 'transform':
|
|
805
|
+
requestAnimationFrame(() => {
|
|
806
|
+
target.style.transform = 'none';
|
|
807
|
+
});
|
|
808
|
+
break;
|
|
809
|
+
|
|
810
|
+
default:
|
|
811
|
+
// Reset to a sensible default
|
|
812
|
+
console.debug(`Using default reversal for ${property}`);
|
|
813
|
+
if (target.getAttribute(`data-initial-${property}`)) {
|
|
814
|
+
requestAnimationFrame(() => {
|
|
815
|
+
target.style[property] = target.getAttribute(`data-initial-${property}`);
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|