@vectoriox/iox-builder 1.4.44 → 1.4.46
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.
|
@@ -1150,9 +1150,10 @@ class InteractionEngineService {
|
|
|
1150
1150
|
const ref = this.overlayService.getNodeRef(node);
|
|
1151
1151
|
if (!ref)
|
|
1152
1152
|
return;
|
|
1153
|
-
|
|
1154
|
-
//
|
|
1155
|
-
|
|
1153
|
+
const inBuilder = this.isBuilderMode();
|
|
1154
|
+
// Apply any pre-states queued for THIS element by earlier-registered nodes.
|
|
1155
|
+
// Skip in builder mode — all elements must remain visible for editing.
|
|
1156
|
+
if (!inBuilder && node.id) {
|
|
1156
1157
|
const pending = this.pendingPreStates.get(node.id);
|
|
1157
1158
|
if (pending) {
|
|
1158
1159
|
for (const action of pending) {
|
|
@@ -1165,21 +1166,20 @@ class InteractionEngineService {
|
|
|
1165
1166
|
return;
|
|
1166
1167
|
const cleanups = [];
|
|
1167
1168
|
for (const ix of node.interactions) {
|
|
1168
|
-
//
|
|
1169
|
-
//
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
this.pendingPreStates.set(action.target, list);
|
|
1169
|
+
// Pre-state: hide elements before their entrance animation fires.
|
|
1170
|
+
// Skipped in builder so elements are always editable on the canvas.
|
|
1171
|
+
if (!inBuilder) {
|
|
1172
|
+
for (const action of ix.actions) {
|
|
1173
|
+
if (this.ENTRANCE_TYPES.has(action.type)) {
|
|
1174
|
+
const target = this.resolveTarget(node, action);
|
|
1175
|
+
if (target) {
|
|
1176
|
+
this.applyPreState(target, action);
|
|
1177
|
+
}
|
|
1178
|
+
else if (action.target && action.target !== 'self') {
|
|
1179
|
+
const list = this.pendingPreStates.get(action.target) ?? [];
|
|
1180
|
+
list.push(action);
|
|
1181
|
+
this.pendingPreStates.set(action.target, list);
|
|
1182
|
+
}
|
|
1183
1183
|
}
|
|
1184
1184
|
}
|
|
1185
1185
|
}
|
|
@@ -1251,10 +1251,23 @@ class InteractionEngineService {
|
|
|
1251
1251
|
replay(node) {
|
|
1252
1252
|
if (!node.interactions?.length)
|
|
1253
1253
|
return;
|
|
1254
|
-
// Cancel any in-progress animations first to reset the element cleanly.
|
|
1255
1254
|
const ref = this.overlayService.getNodeRef(node);
|
|
1256
1255
|
if (ref) {
|
|
1257
1256
|
ref.element.getAnimations().forEach(a => a.cancel());
|
|
1257
|
+
// Clear any leftover inline styles so the pre-state applies cleanly.
|
|
1258
|
+
this.clearInlineAnimationStyles(ref.element);
|
|
1259
|
+
}
|
|
1260
|
+
// In builder mode pre-state is never applied on attach, so apply it now
|
|
1261
|
+
// to give an accurate hidden→visible preview. It is cleaned up via
|
|
1262
|
+
// executeAction's anim.finished handler once the animation completes.
|
|
1263
|
+
for (const ix of node.interactions) {
|
|
1264
|
+
for (const action of ix.actions) {
|
|
1265
|
+
if (this.ENTRANCE_TYPES.has(action.type)) {
|
|
1266
|
+
const target = this.resolveTarget(node, action);
|
|
1267
|
+
if (target)
|
|
1268
|
+
this.applyPreState(target, action);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1258
1271
|
}
|
|
1259
1272
|
for (const ix of node.interactions) {
|
|
1260
1273
|
this.runActions(node, ix.actions);
|
|
@@ -1262,6 +1275,11 @@ class InteractionEngineService {
|
|
|
1262
1275
|
}
|
|
1263
1276
|
// ── Private ──────────────────────────────────────────────
|
|
1264
1277
|
attachInteraction(node, ix, element) {
|
|
1278
|
+
// In builder mode, automatic triggers don't auto-fire — use the play button instead.
|
|
1279
|
+
// Click/hover remain active so users can test those interactions on the canvas.
|
|
1280
|
+
if (this.isBuilderMode() && (ix.trigger === 'pageLoad' || ix.trigger === 'viewportEnter' || ix.trigger === 'scrollProgress')) {
|
|
1281
|
+
return () => { };
|
|
1282
|
+
}
|
|
1265
1283
|
switch (ix.trigger) {
|
|
1266
1284
|
case 'pageLoad':
|
|
1267
1285
|
return this.attachPageLoad(node, ix, element);
|
|
@@ -1280,9 +1298,13 @@ class InteractionEngineService {
|
|
|
1280
1298
|
}
|
|
1281
1299
|
// ── Triggers ─────────────────────────────────────────────
|
|
1282
1300
|
attachPageLoad(node, ix, element) {
|
|
1283
|
-
// Execute immediately (next microtask to let rendering settle)
|
|
1284
1301
|
const timer = setTimeout(() => {
|
|
1285
|
-
this.
|
|
1302
|
+
if (this.hasPreStatedAncestor(element)) {
|
|
1303
|
+
this.deferUntilVisible(element, () => this.runActions(node, ix.actions));
|
|
1304
|
+
}
|
|
1305
|
+
else {
|
|
1306
|
+
this.runActions(node, ix.actions);
|
|
1307
|
+
}
|
|
1286
1308
|
}, 50);
|
|
1287
1309
|
return () => clearTimeout(timer);
|
|
1288
1310
|
}
|
|
@@ -1294,6 +1316,17 @@ class InteractionEngineService {
|
|
|
1294
1316
|
const key = ix.id;
|
|
1295
1317
|
if (ix.actions.some(a => a.once) && firedSet.has(key))
|
|
1296
1318
|
continue;
|
|
1319
|
+
// Element is in viewport but may be inside a still-fading parent.
|
|
1320
|
+
// Defer until all pre-stated ancestors finish their entrance animation.
|
|
1321
|
+
if (this.hasPreStatedAncestor(element)) {
|
|
1322
|
+
this.deferUntilVisible(element, () => {
|
|
1323
|
+
if (ix.actions.some(a => a.once) && firedSet.has(key))
|
|
1324
|
+
return;
|
|
1325
|
+
firedSet.add(key);
|
|
1326
|
+
this.runActions(node, ix.actions);
|
|
1327
|
+
});
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1297
1330
|
firedSet.add(key);
|
|
1298
1331
|
this.runActions(node, ix.actions);
|
|
1299
1332
|
}
|
|
@@ -1302,6 +1335,31 @@ class InteractionEngineService {
|
|
|
1302
1335
|
observer.observe(element);
|
|
1303
1336
|
return () => observer.disconnect();
|
|
1304
1337
|
}
|
|
1338
|
+
isBuilderMode() {
|
|
1339
|
+
return document.body.classList.contains('builder-active');
|
|
1340
|
+
}
|
|
1341
|
+
/** Returns true if any DOM ancestor of element is currently faded out via pre-state. */
|
|
1342
|
+
hasPreStatedAncestor(element) {
|
|
1343
|
+
let el = element.parentElement;
|
|
1344
|
+
while (el && el !== document.body) {
|
|
1345
|
+
if (this.preStatedElements.has(el))
|
|
1346
|
+
return true;
|
|
1347
|
+
el = el.parentElement;
|
|
1348
|
+
}
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
/** Polls via RAF until no ancestor is in pre-state, then fires callback. */
|
|
1352
|
+
deferUntilVisible(element, callback) {
|
|
1353
|
+
const poll = () => {
|
|
1354
|
+
if (!this.hasPreStatedAncestor(element)) {
|
|
1355
|
+
callback();
|
|
1356
|
+
}
|
|
1357
|
+
else {
|
|
1358
|
+
requestAnimationFrame(poll);
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
requestAnimationFrame(poll);
|
|
1362
|
+
}
|
|
1305
1363
|
attachClick(node, ix, element) {
|
|
1306
1364
|
const handler = () => {
|
|
1307
1365
|
if (ix.reverseActions?.length) {
|
|
@@ -1368,10 +1426,13 @@ class InteractionEngineService {
|
|
|
1368
1426
|
fill: 'both',
|
|
1369
1427
|
});
|
|
1370
1428
|
if (this.ENTRANCE_TYPES.has(action.type)) {
|
|
1371
|
-
// Once the entrance animation finishes the element is fully visible —
|
|
1372
|
-
// restore pointer events so it can be interacted with.
|
|
1373
1429
|
anim.finished.then(() => {
|
|
1374
1430
|
element.style.removeProperty('pointer-events');
|
|
1431
|
+
this.preStatedElements.delete(element);
|
|
1432
|
+
// Builder: clear inline pre-state so cancelling animations later
|
|
1433
|
+
// doesn't leave the element invisible after a play preview.
|
|
1434
|
+
if (this.isBuilderMode())
|
|
1435
|
+
this.clearInlineAnimationStyles(element);
|
|
1375
1436
|
}).catch(() => { });
|
|
1376
1437
|
}
|
|
1377
1438
|
else if (this.EXIT_TYPES.has(action.type)) {
|