Skip to content

Commit

Permalink
sticky tracker updates
Browse files Browse the repository at this point in the history
  • Loading branch information
xelaint authored and damienwebdev committed Jul 17, 2024
1 parent 3037e1e commit 87586d0
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 43 deletions.
8 changes: 8 additions & 0 deletions libs/design/scss/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,11 @@ h6 {
margin: 0;
padding: 0;
}

.daff-sticky-tracker {
position: relative;
left: 0;
right: 0;
height: 1px;
visibility: hidden;
}
132 changes: 89 additions & 43 deletions libs/design/src/core/sticky-tracker/sticky-tracker.directive.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,109 @@
import { DOCUMENT } from '@angular/common';
import {
Directive,
ElementRef,
EventEmitter,
Inject,
OnDestroy,
OnInit,
Output,
} from '@angular/core';

export const sumPx = (...px: string[]): string => (
px.reduce((acc, curr) => acc + parseInt(curr.replace(/px/, ''), 10), 0) + 'px'
px.reduce((acc, curr) => acc + parseFloat(curr.replace(/px/, '')), 0) + 'px'
);

export const negativePx = (px: string) => parseFloat(px.replace(/px/, '')) * -1 + 'px';

@Directive({
selector: '[daffStickyTracker]',
standalone: true,
})
export class DaffStickyTrackerDirective implements OnDestroy {
observer: IntersectionObserver;
export class DaffStickyTrackerDirective implements OnDestroy, OnInit {
observer: IntersectionObserver | undefined;

private _nativeElement: HTMLElement;

private _marker: Element | null = null;

@Output() stickyChanged: EventEmitter<boolean> = new EventEmitter<boolean>();

constructor(
private elementRef: ElementRef,
@Inject(DOCUMENT) private document: Document,
) { }

private createMarker(
position: { bottom?: string; top?: string } | undefined = undefined,
) {
const mark = this.document.createElement('div');
mark.classList.add('daff-sticky-tracker');
if (position?.top) {
mark.style.top = position.top;
}
if (position?.bottom) {
mark.style.bottom = negativePx(position.bottom);
}
return mark;
}

constructor(private elementRef: ElementRef) {
ngOnInit() {
this._nativeElement = this.elementRef.nativeElement;
const style = getComputedStyle(this.elementRef.nativeElement);
const top = style.top;
const height = style.height;
const bottom = style.bottom;

let rootMargin = '0px 0px 0px 0px';
let threshold = 1;
if (bottom !== 'auto' && bottom !== '') {
rootMargin = `0px 0px ${sumPx(bottom, '-1px')} 0px`;
threshold = 1;
}

if (top !== 'auto' && top !== '') {
rootMargin = `${sumPx(top, '-1px')} 0px 0px 0px`;
threshold = 0.98;
}

this.observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
console.log(
this.elementRef.nativeElement.tagName,
entry.intersectionRatio,
entry.isIntersecting,
entry,
);
if (!entry.isIntersecting) {
this.elementRef.nativeElement.classList.add('daff-sticky');
} else {
this.elementRef.nativeElement.classList.remove('daff-sticky');
}
});
},
{
rootMargin,
threshold: [threshold],
},
);
this.observer.observe(this.elementRef.nativeElement);
if (style.position !== 'sticky') {
return;
}

//This can happen some times during component instantiation.
if (style.top === '' || style.bottom === '') {
return;
}

// If both are auto, do nothing.
if (style.bottom === 'auto' && style.top === 'auto') {
return;
}

//If they're both set to specific values, I don't know what to do.
if (style.bottom !== 'auto' && style.top !== 'auto') {
return;
}

this.observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
this._nativeElement.classList.toggle(
'daff-sticky',
entry.intersectionRatio < 1,
);
});
});

if (style.bottom !== 'auto') {
this._marker = this._nativeElement.insertAdjacentElement(
'afterend',
this.createMarker({
bottom: style.bottom,
}),
);
}

if (style.top !== 'auto') {
this._marker = this._nativeElement.insertAdjacentElement(
'beforebegin',
this.createMarker({
top: style.top,
}),
);
}

if (!this._marker) {
throw new Error('DaffStickyTracker error');
}
this.observer.observe(this._marker);
}

ngOnDestroy() {
this.observer.disconnect();
this.observer?.disconnect();
this._marker?.remove();
}
}

0 comments on commit 87586d0

Please sign in to comment.