@mozaic-ds/angular 2.1.2 → 2.1.3
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.
|
@@ -4950,7 +4950,11 @@ const VIEWPORT_HEIGHT_PX = 300;
|
|
|
4950
4950
|
class MozComboboxComponent {
|
|
4951
4951
|
_doc = inject(DOCUMENT);
|
|
4952
4952
|
_overlay = inject(Overlay);
|
|
4953
|
-
|
|
4953
|
+
_appRef = inject(ApplicationRef);
|
|
4954
|
+
/** rAF handle for the scroll-driven change-detection loop (see _kickViewportTick). */
|
|
4955
|
+
_viewportTickRaf = null;
|
|
4956
|
+
/** Timestamp of the last viewport scroll event, used to stop the tick loop when idle. */
|
|
4957
|
+
_lastViewportScrollTs = 0;
|
|
4954
4958
|
/**
|
|
4955
4959
|
* No-op scroll strategy: the dropdown embeds a CDK virtual-scroll viewport,
|
|
4956
4960
|
* which is a global `CdkScrollable`. With the default `reposition` strategy,
|
|
@@ -5251,17 +5255,39 @@ class MozComboboxComponent {
|
|
|
5251
5255
|
}
|
|
5252
5256
|
}
|
|
5253
5257
|
});
|
|
5254
|
-
// Zoneless support
|
|
5255
|
-
//
|
|
5256
|
-
//
|
|
5257
|
-
//
|
|
5258
|
-
//
|
|
5258
|
+
// Zoneless support for the virtual-scroll viewport.
|
|
5259
|
+
//
|
|
5260
|
+
// The viewport lives inside the CDK connected-overlay portal, so it CANNOT
|
|
5261
|
+
// be reached through `viewChild()` (the portal renders in a separate view
|
|
5262
|
+
// container). On Angular/CDK 22 the viewport applies its content transform
|
|
5263
|
+
// from an `effect()` that only runs during an ApplicationRef tick; in
|
|
5264
|
+
// zoneless mode no tick is scheduled while the user scrolls the list, so the
|
|
5265
|
+
// rendered window freezes and the panel appears to "bounce" without ever
|
|
5266
|
+
// reaching the bottom. (CDK 21 used a different path and was unaffected,
|
|
5267
|
+
// which is why Storybook on 21 looked fine while the 22 consumer bounced.)
|
|
5268
|
+
//
|
|
5269
|
+
// Fix: while the dropdown is open, listen for scroll events on the viewport
|
|
5270
|
+
// in the capture phase (scroll does not bubble) and drive change detection
|
|
5271
|
+
// for a few frames after each scroll, restoring the per-frame CD that
|
|
5272
|
+
// Zone.js would otherwise provide.
|
|
5259
5273
|
effect((onCleanup) => {
|
|
5260
|
-
|
|
5261
|
-
if (!viewport)
|
|
5274
|
+
if (!this.isOpen())
|
|
5262
5275
|
return;
|
|
5263
|
-
const
|
|
5264
|
-
|
|
5276
|
+
const viewportId = `${this.comboboxId}-viewport`;
|
|
5277
|
+
const onScroll = (event) => {
|
|
5278
|
+
const target = event.target;
|
|
5279
|
+
if (target?.id === viewportId) {
|
|
5280
|
+
this._kickViewportTick();
|
|
5281
|
+
}
|
|
5282
|
+
};
|
|
5283
|
+
this._doc.addEventListener('scroll', onScroll, true);
|
|
5284
|
+
onCleanup(() => {
|
|
5285
|
+
this._doc.removeEventListener('scroll', onScroll, true);
|
|
5286
|
+
if (this._viewportTickRaf !== null) {
|
|
5287
|
+
cancelAnimationFrame(this._viewportTickRaf);
|
|
5288
|
+
this._viewportTickRaf = null;
|
|
5289
|
+
}
|
|
5290
|
+
});
|
|
5265
5291
|
});
|
|
5266
5292
|
// Inject global overlay styles — CDK teleports content outside the
|
|
5267
5293
|
// component host so scoped CSS never reaches .cdk-overlay-pane.
|
|
@@ -5572,6 +5598,35 @@ class MozComboboxComponent {
|
|
|
5572
5598
|
});
|
|
5573
5599
|
}
|
|
5574
5600
|
}
|
|
5601
|
+
/**
|
|
5602
|
+
* Drive change detection for a short window after a viewport scroll so the
|
|
5603
|
+
* CDK virtual-scroll viewport (inside the overlay portal) applies its content
|
|
5604
|
+
* transform in zoneless mode. Runs at most one rAF loop at a time; each new
|
|
5605
|
+
* scroll event extends the window, and the loop stops ~200ms after the last
|
|
5606
|
+
* scroll. `tick()` is guarded because it throws if called during an ongoing
|
|
5607
|
+
* change-detection pass (it never is here — rAF callbacks run outside CD).
|
|
5608
|
+
*/
|
|
5609
|
+
_kickViewportTick() {
|
|
5610
|
+
this._lastViewportScrollTs = Date.now();
|
|
5611
|
+
if (this._viewportTickRaf !== null) {
|
|
5612
|
+
return;
|
|
5613
|
+
}
|
|
5614
|
+
const loop = () => {
|
|
5615
|
+
try {
|
|
5616
|
+
this._appRef.tick();
|
|
5617
|
+
}
|
|
5618
|
+
catch {
|
|
5619
|
+
// tick() called during an active CD pass — safe to skip this frame.
|
|
5620
|
+
}
|
|
5621
|
+
if (Date.now() - this._lastViewportScrollTs < 200) {
|
|
5622
|
+
this._viewportTickRaf = requestAnimationFrame(loop);
|
|
5623
|
+
}
|
|
5624
|
+
else {
|
|
5625
|
+
this._viewportTickRaf = null;
|
|
5626
|
+
}
|
|
5627
|
+
};
|
|
5628
|
+
this._viewportTickRaf = requestAnimationFrame(loop);
|
|
5629
|
+
}
|
|
5575
5630
|
/** Coerce the current value into an array (safe for .some/.filter/.every). */
|
|
5576
5631
|
_currentValueAsArray() {
|
|
5577
5632
|
const raw = this.value();
|