@vectoriox/iox-builder 1.5.7 → 1.5.9

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.
@@ -1278,9 +1278,15 @@ class InteractionEngineService {
1278
1278
  const cleanups = [];
1279
1279
  for (const ix of node.interactions) {
1280
1280
  // Pre-state: hide target elements before their entrance animation fires.
1281
- // In builder mode: skip only suppressed triggers (pageLoad, scrollProgress).
1282
- // viewportEnter IS active in builder — elements must be hidden before trigger.
1283
- const skipPreState = inBuilder && (ix.trigger === 'pageLoad' || ix.trigger === 'scrollProgress');
1281
+ // In builder mode, pre-state is skipped for every SUPPRESSED trigger
1282
+ // (pageLoad, scrollProgress, viewportEnter — see attachInteraction) so the
1283
+ // element appears normally on the canvas. If we applied pre-state without
1284
+ // attaching the trigger, the element would stay opacity:0 forever. The play
1285
+ // button (_replay) re-applies pre-state on demand for an accurate preview.
1286
+ // click/hover keep pre-state because those triggers DO fire on the canvas.
1287
+ const skipPreState = inBuilder && (ix.trigger === 'pageLoad' ||
1288
+ ix.trigger === 'scrollProgress' ||
1289
+ ix.trigger === 'viewportEnter');
1284
1290
  if (!skipPreState) {
1285
1291
  for (const action of ix.actions) {
1286
1292
  if (this.ENTRANCE_TYPES.has(action.type)) {
@@ -1407,9 +1413,14 @@ class InteractionEngineService {
1407
1413
  }
1408
1414
  // ── Private ──────────────────────────────────────────────
1409
1415
  attachInteraction(node, ix, element) {
1410
- // In builder mode, automatic triggers don't auto-fire — use the play button instead.
1416
+ // In builder mode, scroll-based and time-based triggers don't auto-fire — use the
1417
+ // play button instead. viewportEnter is skipped because the IntersectionObserver
1418
+ // fires immediately (element is visible in the canvas) and its WAAPI animation +
1419
+ // the overlay ResizeObserver feedback loop triggers NG0103 during synchronize().
1411
1420
  // Click/hover remain active so users can test those interactions on the canvas.
1412
- if (this.isBuilderMode() && (ix.trigger === 'pageLoad' || ix.trigger === 'scrollProgress')) {
1421
+ if (this.isBuilderMode() && (ix.trigger === 'pageLoad' ||
1422
+ ix.trigger === 'scrollProgress' ||
1423
+ ix.trigger === 'viewportEnter')) {
1413
1424
  return () => { };
1414
1425
  }
1415
1426
  switch (ix.trigger) {
@@ -5554,6 +5565,7 @@ class SliderContainerComponent {
5554
5565
  this._orgId = 'default';
5555
5566
  this.instanceRegistry = inject(ComponentInstanceRegistryService);
5556
5567
  this.interactionEngine = inject(InteractionEngineService);
5568
+ this.ngZone = inject(NgZone);
5557
5569
  this.isPreview = !!isPreview;
5558
5570
  }
5559
5571
  ngOnInit() {
@@ -5572,7 +5584,11 @@ class SliderContainerComponent {
5572
5584
  }
5573
5585
  }
5574
5586
  ngAfterViewInit() {
5575
- this._initRafId = requestAnimationFrame(() => this._initSwiper());
5587
+ // Run outside Angular's zone so Swiper's internal ResizeObserver, MutationObserver,
5588
+ // and RAF-based animation loops don't trigger unnecessary CD ticks.
5589
+ this.ngZone.runOutsideAngular(() => {
5590
+ this._initRafId = requestAnimationFrame(() => this._initSwiper());
5591
+ });
5576
5592
  }
5577
5593
  ngOnChanges(changes) {
5578
5594
  if (!this._swiper)
@@ -5600,7 +5616,9 @@ class SliderContainerComponent {
5600
5616
  const hasConfigChange = Object.keys(changes).some(k => relevantKeys.has(k));
5601
5617
  if (hasConfigChange) {
5602
5618
  this._destroySwiper();
5603
- this._initRafId = requestAnimationFrame(() => this._initSwiper());
5619
+ this.ngZone.runOutsideAngular(() => {
5620
+ this._initRafId = requestAnimationFrame(() => this._initSwiper());
5621
+ });
5604
5622
  }
5605
5623
  }
5606
5624
  ngOnDestroy() {
@@ -5615,9 +5633,10 @@ class SliderContainerComponent {
5615
5633
  if (this._source)
5616
5634
  return; // repeat mode: drops disabled, slides come from data source
5617
5635
  this.dragEngine.handleDrop(this.children, event, this.dropListId, this.cdr);
5618
- // Sync Swiper's internal slide list after drag-drop reorder
5619
5636
  if (this._swiper) {
5620
- requestAnimationFrame(() => this._swiper?.update());
5637
+ this.ngZone.runOutsideAngular(() => {
5638
+ requestAnimationFrame(() => this._swiper?.update());
5639
+ });
5621
5640
  }
5622
5641
  }
5623
5642
  // ── Data fetching ───────────────────────────────────────────────────────────
@@ -5692,7 +5711,9 @@ class SliderContainerComponent {
5692
5711
  }
5693
5712
  _scheduleReinit() {
5694
5713
  this._destroySwiper();
5695
- this._initRafId = requestAnimationFrame(() => this._initSwiper());
5714
+ this.ngZone.runOutsideAngular(() => {
5715
+ this._initRafId = requestAnimationFrame(() => this._initSwiper());
5716
+ });
5696
5717
  }
5697
5718
  // ── Swiper lifecycle ────────────────────────────────────────────────────────
5698
5719
  async _initSwiper() {