{"version":3,"file":"ngwr-affix.mjs","sources":["../../../projects/lib/affix/affix.ts","../../../projects/lib/affix/ngwr-affix.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceNumberProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Directive, ElementRef, PLATFORM_ID, afterNextRender, inject, input, output } from '@angular/core';\n\n/**\n * Stick-on-scroll directive. Combines native CSS `position: sticky` with\n * an `IntersectionObserver`-driven `--affixed` state class, so consumers\n * can style the element differently while it's pinned (e.g. add a\n * shadow, change the background, shrink the height).\n *\n * The host gets `position: sticky; top: ${offsetTop}px;` inline. A tiny\n * sentinel `<div>` is inserted just before the host — when the sentinel\n * scrolls out of view, the host is \"stuck\" and gets `wr-affix--active`\n * + an `(wrAffixChange)` emission.\n *\n * Works inside any scroll container without configuration — CSS sticky\n * picks the nearest scrollable ancestor automatically.\n *\n * @example\n * ```html\n * <header wrAffix [wrAffixOffsetTop]=\"0\">\n *   <!-- adds a shadow once stuck -->\n * </header>\n * ```\n *\n * ```scss\n * header.wr-affix.wr-affix--active {\n *   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n * }\n * ```\n */\n@Directive({\n  selector: '[wrAffix]',\n  host: {\n    class: 'wr-affix',\n    '[style.position]': '\"sticky\"',\n    '[style.top.px]': 'offsetTop()',\n  },\n})\nexport class WrAffix {\n  /** Pixels from the top of the scroll container when stuck. @default 0 */\n  readonly offsetTop = input(0, {\n    alias: 'wrAffixOffsetTop',\n    transform: (v: unknown): number => coerceNumberProperty(v, 0),\n  });\n\n  /** Emits `true` when the element becomes affixed, `false` when it unsticks. */\n  // eslint-disable-next-line @angular-eslint/no-output-rename -- keep wr-prefixed binding to match `[wrAffix]`\n  readonly affixChange = output<boolean>({ alias: 'wrAffixChange' });\n\n  private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n  constructor() {\n    if (!this.isBrowser) return;\n\n    afterNextRender(() => {\n      const el = this.host.nativeElement;\n      const parent = el.parentElement;\n      if (!parent) return;\n\n      // Sentinel: an empty zero-height block placed immediately before\n      // the host. When the sentinel scrolls out of view, the host is\n      // necessarily \"stuck\" at the configured offset.\n      const sentinel = el.ownerDocument.createElement('div');\n      sentinel.className = 'wr-affix__sentinel';\n      sentinel.setAttribute('aria-hidden', 'true');\n      sentinel.style.cssText = 'height:0;width:100%;margin:0;padding:0;pointer-events:none;';\n      parent.insertBefore(sentinel, el);\n\n      const observer = new IntersectionObserver(\n        ([entry]) => {\n          const affixed = !entry.isIntersecting;\n          el.classList.toggle('wr-affix--active', affixed);\n          this.affixChange.emit(affixed);\n        },\n        {\n          // Trigger when the sentinel's top crosses the offset line.\n          rootMargin: `-${this.offsetTop()}px 0px 0px 0px`,\n          threshold: [0],\n        }\n      );\n      observer.observe(sentinel);\n\n      this.destroyRef.onDestroy(() => {\n        observer.disconnect();\n        sentinel.remove();\n        el.classList.remove('wr-affix--active');\n      });\n    });\n  }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}