@ascentgl/ads-ui 21.113.0 → 21.114.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.
@@ -6316,7 +6316,8 @@ class AdsDatepickerComponent extends AdsDatetimepickerComponent {
6316
6316
  ngOnDestroy() {
6317
6317
  super.ngOnDestroy();
6318
6318
  this.intersectionObserver?.disconnect();
6319
- this.teardownBackdropScrollPassthrough();
6319
+ this.scrollPassthroughCleanup?.();
6320
+ this.scrollPassthroughCleanup = undefined;
6320
6321
  }
6321
6322
  /** @ignore */
6322
6323
  setupIntersectionObserver() {
@@ -6335,54 +6336,70 @@ class AdsDatepickerComponent extends AdsDatetimepickerComponent {
6335
6336
  }
6336
6337
  /**
6337
6338
  * @ignore
6338
- * When the calendar overlay opens, the CDK backdrop (pointer-events: auto)
6339
- * covers the entire viewport and intercepts wheel events, preventing scroll
6340
- * on underlying containers. Forward those events to the nearest scrollable ancestor.
6339
+ * The CDK overlay backdrop has `pointer-events: auto` which intercepts all
6340
+ * pointer / wheel events, preventing native scroll on underlying containers.
6341
+ * Disabling pointer events on the backdrop lets the browser handle scrolling
6342
+ * natively (preserving momentum / inertia). A document-level pointerdown
6343
+ * listener replaces the lost backdrop click-to-close behaviour.
6341
6344
  */
6342
6345
  onOpened() {
6343
6346
  super.onOpened();
6344
- this.setupBackdropScrollPassthrough();
6347
+ this.setupScrollPassthrough();
6345
6348
  }
6346
6349
  /** @ignore */
6347
6350
  onClosed() {
6348
- this.teardownBackdropScrollPassthrough();
6351
+ this.scrollPassthroughCleanup?.();
6352
+ this.scrollPassthroughCleanup = undefined;
6349
6353
  super.onClosed();
6350
6354
  }
6351
6355
  /** @ignore */
6352
- setupBackdropScrollPassthrough() {
6353
- this.teardownBackdropScrollPassthrough();
6356
+ setupScrollPassthrough() {
6357
+ this.scrollPassthroughCleanup?.();
6358
+ this.scrollPassthroughCleanup = undefined;
6354
6359
  const container = this.overlayContainerRef.getContainerElement();
6355
6360
  const backdrop = container.querySelector('.cdk-overlay-backdrop');
6356
- if (!backdrop)
6357
- return;
6358
- const scrollTarget = this.findScrollableAncestor(this.elementRef.nativeElement);
6359
- if (!scrollTarget)
6360
- return;
6361
+ // Disable pointer events on the backdrop so that wheel / touch events
6362
+ // reach the scroll container natively. This preserves momentum scrolling
6363
+ // and avoids the scroll-stop when closeOnOutOfView closes the picker mid-scroll.
6364
+ if (backdrop) {
6365
+ backdrop.style.pointerEvents = 'none';
6366
+ }
6361
6367
  const cleanupFns = [];
6362
- // Forward wheel events from the backdrop to the scrollable ancestor
6363
- // so that the page can still be scrolled while the calendar is open.
6364
- const onWheel = (event) => {
6365
- scrollTarget.scrollTop += event.deltaY;
6366
- scrollTarget.scrollLeft += event.deltaX;
6367
- };
6368
- backdrop.addEventListener('wheel', onWheel, { passive: true });
6369
- cleanupFns.push(() => backdrop.removeEventListener('wheel', onWheel));
6370
- // Reposition the calendar overlay when the scroll container scrolls,
6371
- // keeping the popup attached to the input (same behaviour as ads-dropdown).
6368
+ // Replace the backdrop click-to-close with a document-level pointerdown
6369
+ // listener. Delay one animation frame so the interaction that opened the
6370
+ // picker does not immediately close it.
6371
+ let pointerDownCleanup;
6372
+ const rafId = requestAnimationFrame(() => {
6373
+ const onPointerDown = (event) => {
6374
+ if (!this.picker?.opened)
6375
+ return;
6376
+ const overlayPane = container.querySelector('.cdk-overlay-pane');
6377
+ const clickedInside = overlayPane?.contains(event.target) ||
6378
+ this.elementRef.nativeElement.contains(event.target);
6379
+ if (!clickedInside) {
6380
+ this.picker.close();
6381
+ }
6382
+ };
6383
+ document.addEventListener('pointerdown', onPointerDown);
6384
+ pointerDownCleanup = () => document.removeEventListener('pointerdown', onPointerDown);
6385
+ });
6386
+ cleanupFns.push(() => {
6387
+ cancelAnimationFrame(rafId);
6388
+ pointerDownCleanup?.();
6389
+ });
6390
+ // Reposition the calendar overlay when a non-document scroll container scrolls.
6372
6391
  // CDK ScrollDispatcher only detects window scroll and CdkScrollable directives,
6373
6392
  // not arbitrary overflow containers, so we trigger the update manually.
6374
- const onScroll = () => {
6375
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6376
- this.picker?._popupRef?.updatePosition();
6377
- };
6378
- scrollTarget.addEventListener('scroll', onScroll, { passive: true });
6379
- cleanupFns.push(() => scrollTarget.removeEventListener('scroll', onScroll));
6380
- this.backdropWheelCleanup = () => cleanupFns.forEach((fn) => fn());
6381
- }
6382
- /** @ignore */
6383
- teardownBackdropScrollPassthrough() {
6384
- this.backdropWheelCleanup?.();
6385
- this.backdropWheelCleanup = undefined;
6393
+ const scrollTarget = this.findScrollableAncestor(this.elementRef.nativeElement);
6394
+ if (scrollTarget) {
6395
+ const onScroll = () => {
6396
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6397
+ this.picker?._popupRef?.updatePosition();
6398
+ };
6399
+ scrollTarget.addEventListener('scroll', onScroll, { passive: true });
6400
+ cleanupFns.push(() => scrollTarget.removeEventListener('scroll', onScroll));
6401
+ }
6402
+ this.scrollPassthroughCleanup = () => cleanupFns.forEach((fn) => fn());
6386
6403
  }
6387
6404
  /** @ignore - Walk up the DOM to find the first ancestor with overflow-y: auto|scroll */
6388
6405
  findScrollableAncestor(node) {