-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
03e6062
commit e173771
Showing
10 changed files
with
499 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
...mponents/core/src/lib/modules/scroll-shadow/fixtures/scroll-shadow.component.fixture.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<div class="scroll-shadow-test-wrapper"> | ||
<div | ||
class="scroll-shadow-test-header" | ||
[ngStyle]="{ | ||
'box-shadow': scrollShadow?.topShadow ?? 'none' | ||
}" | ||
></div> | ||
<div | ||
class="scroll-shadow-test-body" | ||
(skyScrollShadow)="scrollShadowChange($event)" | ||
[skyScrollShadowEnabled]="enabled" | ||
> | ||
<span | ||
class="scroll-shadow-test-content" | ||
[ngStyle]="{ | ||
'height.px': height | ||
}" | ||
></span> | ||
</div> | ||
<div | ||
class="scroll-shadow-test-footer" | ||
[ngStyle]="{ | ||
'box-shadow': scrollShadow?.bottomShadow ?? 'none' | ||
}" | ||
></div> | ||
</div> |
17 changes: 17 additions & 0 deletions
17
...mponents/core/src/lib/modules/scroll-shadow/fixtures/scroll-shadow.component.fixture.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
:is(.scroll-shadow-test-header, .scroll-shadow-test-footer) { | ||
height: 100px; | ||
} | ||
|
||
.scroll-shadow-test-body { | ||
overflow-y: scroll; | ||
display: block; | ||
max-height: calc(100vh - 200px); | ||
} | ||
|
||
.scroll-shadow-test-content { | ||
display: block; | ||
} | ||
|
||
.scroll-shadow-test-wrapper { | ||
max-height: 100vh; | ||
} |
25 changes: 25 additions & 0 deletions
25
...components/core/src/lib/modules/scroll-shadow/fixtures/scroll-shadow.component.fixture.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { CommonModule } from '@angular/common'; | ||
import { ChangeDetectorRef, Component, inject } from '@angular/core'; | ||
|
||
import { SkyScrollShadowEventArgs } from '../scroll-shadow-event-args'; | ||
import { SkyScrollShadowDirective } from '../scroll-shadow.directive'; | ||
|
||
@Component({ | ||
selector: 'sky-scroll-shadow-fixture', | ||
styleUrls: ['./scroll-shadow.component.fixture.scss'], | ||
templateUrl: './scroll-shadow.component.fixture.html', | ||
imports: [CommonModule, SkyScrollShadowDirective], | ||
standalone: true, | ||
}) | ||
export class ScrollShadowFixtureComponent { | ||
public enabled = true; | ||
public height = 400; | ||
public scrollShadow: SkyScrollShadowEventArgs | undefined; | ||
|
||
#changeDetector = inject(ChangeDetectorRef); | ||
|
||
public scrollShadowChange(args: SkyScrollShadowEventArgs): void { | ||
this.scrollShadow = args; | ||
this.#changeDetector.markForCheck(); | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...s/modal/modal-scroll-shadow-event-args.ts → ...scroll-shadow/scroll-shadow-event-args.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
libs/components/core/src/lib/modules/scroll-shadow/scroll-shadow.directive.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import { | ||
ComponentFixture, | ||
TestBed, | ||
fakeAsync, | ||
tick, | ||
} from '@angular/core/testing'; | ||
import { SkyAppTestUtility } from '@skyux-sdk/testing'; | ||
|
||
import { ScrollShadowFixtureComponent } from './fixtures/scroll-shadow.component.fixture'; | ||
|
||
// Wait for the next change detection cycle. This avoids having nested setTimeout() calls | ||
// and using the Jasmine done() function. | ||
function waitForMutationObserver(): Promise<void> { | ||
return new Promise<void>((resolve) => { | ||
setTimeout(() => resolve()); | ||
}); | ||
} | ||
|
||
describe('Scroll shadow directive', () => { | ||
function getScrollBody(): HTMLElement | null { | ||
return document.querySelector<HTMLElement>('.scroll-shadow-test-body'); | ||
} | ||
|
||
function getScrollFooter(): HTMLElement | null { | ||
return document.querySelector<HTMLElement>('.scroll-shadow-test-footer'); | ||
} | ||
|
||
function getScrollHeader(): HTMLElement | null { | ||
return document.querySelector<HTMLElement>('.scroll-shadow-test-header'); | ||
} | ||
|
||
function scrollElement(element: HTMLElement | null, yDistance: number): void { | ||
if (element) { | ||
element.scrollTop = yDistance; | ||
SkyAppTestUtility.fireDomEvent(element, 'scroll'); | ||
fixture.detectChanges(); | ||
} | ||
} | ||
|
||
function validateShadow( | ||
el: HTMLElement | null, | ||
expectedAlpha?: number, | ||
): void { | ||
if (!el) { | ||
fail('Element not provided'); | ||
return; | ||
} | ||
|
||
const boxShadowStyle = getComputedStyle(el).boxShadow; | ||
|
||
if (expectedAlpha) { | ||
const rgbaMatch = boxShadowStyle.match( | ||
/rgba\(0,\s*0,\s*0,\s*([0-9.]*)\)/, | ||
); | ||
|
||
if (!(rgbaMatch && rgbaMatch[1])) { | ||
fail('No shadow found'); | ||
} else { | ||
const alpha = parseFloat(rgbaMatch[1]); | ||
|
||
expect(expectedAlpha).toBeCloseTo(alpha, 2); | ||
} | ||
} else { | ||
expect(boxShadowStyle).toBe('none'); | ||
} | ||
} | ||
|
||
let fixture: ComponentFixture<ScrollShadowFixtureComponent>; | ||
let cmp: ScrollShadowFixtureComponent; | ||
|
||
beforeEach(fakeAsync(() => { | ||
TestBed.configureTestingModule({ | ||
imports: [ScrollShadowFixtureComponent], | ||
}); | ||
|
||
fixture = TestBed.createComponent(ScrollShadowFixtureComponent); | ||
cmp = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
tick(); | ||
fixture.detectChanges(); | ||
})); | ||
|
||
it('should not show a shadow when the body is not scrollable when disabled', async () => { | ||
cmp.enabled = false; | ||
fixture.detectChanges(); | ||
await waitForMutationObserver(); | ||
fixture.detectChanges(); | ||
|
||
validateShadow(getScrollFooter()); | ||
validateShadow(getScrollHeader()); | ||
}); | ||
|
||
it('should not show a shadow when the body is scrollable when disabled', async () => { | ||
cmp.height = 800; | ||
cmp.enabled = false; | ||
fixture.detectChanges(); | ||
await waitForMutationObserver(); | ||
fixture.detectChanges(); | ||
|
||
validateShadow(getScrollFooter()); | ||
validateShadow(getScrollHeader()); | ||
}); | ||
|
||
it('should not show a shadow when the body is not scrollable', async () => { | ||
await waitForMutationObserver(); | ||
fixture.detectChanges(); | ||
|
||
validateShadow(getScrollFooter()); | ||
validateShadow(getScrollHeader()); | ||
}); | ||
|
||
it('should progressively show a drop shadow as the modal content scrolls', async () => { | ||
const headerEl = getScrollHeader(); | ||
const contentEl = getScrollBody(); | ||
const footerEl = getScrollFooter(); | ||
|
||
if (!contentEl) { | ||
fail('Content element not found'); | ||
return; | ||
} | ||
|
||
cmp.height = 800; | ||
fixture.detectChanges(); | ||
await waitForMutationObserver(); | ||
fixture.detectChanges(); | ||
|
||
scrollElement(contentEl, 0); | ||
validateShadow(headerEl); | ||
validateShadow(footerEl, 0.3); | ||
|
||
scrollElement(contentEl, 15); | ||
validateShadow(headerEl, 0.15); | ||
validateShadow(footerEl, 0.3); | ||
|
||
scrollElement(contentEl, 30); | ||
validateShadow(headerEl, 0.3); | ||
validateShadow(footerEl, 0.3); | ||
|
||
scrollElement(contentEl, 31); | ||
validateShadow(headerEl, 0.3); | ||
validateShadow(footerEl, 0.3); | ||
|
||
scrollElement( | ||
contentEl, | ||
contentEl.scrollHeight - 15 - contentEl.clientHeight, | ||
); | ||
validateShadow(headerEl, 0.3); | ||
validateShadow(footerEl, 0.15); | ||
|
||
scrollElement(contentEl, contentEl.scrollHeight - contentEl.clientHeight); | ||
validateShadow(headerEl, 0.3); | ||
validateShadow(footerEl); | ||
}); | ||
|
||
it('should update the shadow on window resize', async () => { | ||
const headerEl = getScrollHeader(); | ||
const contentEl = getScrollBody(); | ||
const footerEl = getScrollFooter(); | ||
|
||
if (!contentEl) { | ||
fail('Content element not found'); | ||
return; | ||
} | ||
|
||
cmp.height = 800; | ||
fixture.detectChanges(); | ||
await waitForMutationObserver(); | ||
fixture.detectChanges(); | ||
|
||
validateShadow(headerEl); | ||
validateShadow(footerEl, 0.3); | ||
|
||
spyOnProperty(Element.prototype, 'scrollTop').and.returnValue(15); | ||
SkyAppTestUtility.fireDomEvent(window, 'resize'); | ||
fixture.detectChanges(); | ||
|
||
validateShadow(headerEl, 0.15); | ||
validateShadow(footerEl, 0.3); | ||
}); | ||
}); |
Oops, something went wrong.