Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package-lock=false
2 changes: 0 additions & 2 deletions .prettierignore

This file was deleted.

17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,23 @@ export class AppComponent {
}
```

### Offset example

You can pass any options [Intersection Observer][intersection-observer-api] accepts using the `[inViewportOptions]` property. This allows offsets to be set using the `rootMargin` property. This property works the same as `margin` property in CSS.

#### `app.component.html`

```html
<p
class="foo"
snInViewport
[inViewportOptions]="{
rootMargin: '100px 0px 0px 0px'
}">
Amet tempor excepteur occaecat nulla.
</p>
```

## Development server

Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
Expand Down
17 changes: 17 additions & 0 deletions e2e/src/app.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,21 @@ describe('InViewport Lib E2E Tests', function() {
'sn-viewport--out'
);
});

it('should apply offset to element with options', () => {
page.scrollTo(0, 768 * 2.4);
expect(page.getElementWithOptions().getAttribute('class')).toContain(
'sn-viewport--out'
);

page.scrollTo(0, 768 * 2.5);
expect(page.getElementWithOptions().getAttribute('class')).toContain(
'sn-viewport--in'
);

page.scrollTo(0, 768 * 3.6);
expect(page.getElementWithOptions().getAttribute('class')).not.toContain(
'sn-viewport--in'
);
});
});
4 changes: 4 additions & 0 deletions e2e/src/app.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export class AppPage {
return element(by.css('.element--large'));
}

getElementWithOptions() {
return element(by.css('.element--has-options'));
}

getScrollableInnerElement() {
return element(by.css('.scrollable__inner'));
}
Expand Down
7 changes: 7 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,11 @@ <h1>Scroll down ↓ and right →</h1>

</div>

<p
class="element--has-options"
snInViewport
[inViewportOptions]="options">
Amet tempor excepteur occaecat nulla. Aute deserunt esse duis velit mollit exercitation nisi officia. Anim do irure cillum esse esse ea magna elit. Velit reprehenderit eiusmod aliqua do reprehenderit elit commodo enim do deserunt consequat ea elit. Incididunt dolore officia consectetur anim ex ea commodo ullamco veniam ipsum esse amet cupidatat commodo. Id consequat duis aliqua minim aliquip enim officia elit. Sint est fugiat ex ex proident ad veniam do excepteur.
</p>

<div class="spacer"></div>
11 changes: 11 additions & 0 deletions src/app/app.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
font-family: Roboto, sans-serif;
}

p {
margin: 0;
}

.spacer {
height: 100vh;
width: 200vw;
Expand All @@ -16,6 +20,13 @@
min-height: 200vh;
}

.element--has-options {
&.sn-viewport--in {
background-color: pink;
color: black;
}
}

.scrollable {
height: 200px;
overflow: auto;
Expand Down
3 changes: 3 additions & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { Component } from '@angular/core';
})
export class AppComponent {
highlight = false;
options: IntersectionObserverInit = {
rootMargin: '-100px 0px 50px 0px'
};

onInViewportChange(inViewport: boolean) {
this.highlight = inViewport;
Expand Down
15 changes: 15 additions & 0 deletions src/app/in-viewport/in-viewport.directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ describe('InViewportDirective', () => {
expect(spy).toHaveBeenCalledWith(true);
});

it('should add options to IntersectionObserver', () => {
const spy = jasmine.createSpy('spy').and.returnValue({
observe: () => null,
unobserve: () => null
});
WINDOW_MOCK.IntersectionObserver = spy;
directive.inViewportOptions = { rootMargin: '100px' };
directive.ngAfterViewInit();
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(
jasmine.any(Function),
directive.inViewportOptions
);
});

it('should should unobserve on destroy', () => {
const spy = jasmine.createSpy('spy');
directive.observer.unobserve = spy;
Expand Down
8 changes: 6 additions & 2 deletions src/app/in-viewport/in-viewport.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
Output,
OnDestroy,
AfterViewInit,
Inject
Inject,
Input
} from '@angular/core';
import { WINDOW } from '../window/window-token';

Expand All @@ -32,6 +33,8 @@ import { WINDOW } from '../window/window-token';
})
export class InViewportDirective implements AfterViewInit, OnDestroy {
private inViewport: boolean;
@Input()
inViewportOptions: IntersectionObserverInit;
@Output()
inViewportChange = new EventEmitter<boolean>();
observer: IntersectionObserver;
Expand All @@ -51,7 +54,8 @@ export class InViewportDirective implements AfterViewInit, OnDestroy {
ngAfterViewInit() {
const IntersectionObserver = this.window['IntersectionObserver'];
this.observer = new IntersectionObserver(
this.intersectionObserverCallback.bind(this)
this.intersectionObserverCallback.bind(this),
this.inViewportOptions
);

this.observer.observe(this.el.nativeElement);
Expand Down