Improved flow of observables/emissions

This commit is contained in:
squidfunk
2020-03-16 14:59:59 +01:00
parent 47aa47ee4c
commit 653d535a22
16 changed files with 86 additions and 93 deletions

View File

@@ -92,7 +92,7 @@ export function mountHeader(
): OperatorFunction<HTMLElement, Header> {
return pipe(
switchMap(el => {
const header$ = watchHeader(el, { viewport$ })
const header$ = watchHeader(el)
/* Compute whether the header should switch to page header */
const type$ = useComponent("main")

View File

@@ -28,14 +28,14 @@ import {
pipe
} from "rxjs"
import {
distinctUntilKeyChanged,
finalize,
map,
observeOn,
switchMap,
shareReplay,
tap
} from "rxjs/operators"
import { Viewport } from "browser"
import { watchElementSize } from "browser"
import { Header, HeaderType } from "../_"
import {
@@ -43,17 +43,6 @@ import {
setHeaderTitleActive
} from "../set"
/* ----------------------------------------------------------------------------
* Helper types
* ------------------------------------------------------------------------- */
/**
* Watch options
*/
interface WatchOptions {
viewport$: Observable<Viewport> /* Viewport observable */
}
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
@@ -61,32 +50,32 @@ interface WatchOptions {
/**
* Watch header
*
* The header is wrapped in an observable to pave the way for auto-hiding or
* other dynamic behaviors that may be implemented later on.
*
* @param el - Header element
* @param options - Options
*
* @return Header observable
*/
export function watchHeader(
el: HTMLElement, { viewport$ }: WatchOptions
el: HTMLElement
): Observable<Omit<Header, "type">> {
return viewport$
.pipe(
distinctUntilKeyChanged("size"),
switchMap(() => {
const styles = getComputedStyle(el)
const sticky = [
"sticky", /* Modern browsers */
"-webkit-sticky" /* Safari */
].includes(styles.position)
return of({
sticky,
height: sticky ? el.offsetHeight : 0
})
})
)
const styles = getComputedStyle(el)
if ([
"sticky", /* Modern browsers */
"-webkit-sticky" /* Safari */
].includes(styles.position)) {
return watchElementSize(el)
.pipe(
map(({ height }) => ({
sticky: true,
height
})),
shareReplay(1)
)
} else {
return of({
sticky: false,
height: 0
})
}
}
/* ------------------------------------------------------------------------- */

View File

@@ -29,11 +29,13 @@ import {
} from "rxjs"
import {
distinctUntilChanged,
distinctUntilKeyChanged,
finalize,
map,
observeOn,
pluck,
shareReplay,
switchMap,
tap
} from "rxjs/operators"
@@ -81,17 +83,23 @@ export function watchMain(
/* Compute necessary adjustment for header */
const adjust$ = header$
.pipe(
pluck("height")
pluck("height"),
distinctUntilChanged(),
shareReplay(1)
)
/* Compute the main area's top and bottom markers */
const marker$ = watchElementSize(el)
const marker$ = adjust$
.pipe(
map(({ height }) => ({
top: el.offsetTop,
bottom: el.offsetTop + height
})),
distinctUntilChanged(),
switchMap(() => watchElementSize(el)
.pipe(
map(({ height }) => ({
top: el.offsetTop,
bottom: el.offsetTop + height
}))
)
),
distinctUntilKeyChanged("top"),
shareReplay(1)
)

View File

@@ -25,7 +25,6 @@ import {
Observable,
animationFrameScheduler,
combineLatest,
of,
pipe
} from "rxjs"
import {
@@ -90,15 +89,13 @@ interface ApplyOptions {
export function watchSidebar(
el: HTMLElement, { main$, viewport$ }: WatchOptions
): Observable<Sidebar> {
const inner = el.parentElement!
const outer = inner.parentElement!
const adjust = el.parentElement!.offsetTop
- el.parentElement!.parentElement!.offsetTop
/* Compute the sidebar's available height */
const adjust$ = of(inner.offsetTop - outer.offsetTop)
const height$ = viewport$
const height$ = combineLatest([main$, viewport$])
.pipe(
withLatestFrom(adjust$, main$),
map(([{ offset: { y } }, adjust, { offset, height }]) => (
map(([{ offset, height }, { offset: { y } }]) => (
height
+ Math.min(adjust, Math.max(0, y - offset))
- adjust
@@ -107,12 +104,9 @@ export function watchSidebar(
)
/* Compute whether the sidebar should be locked */
const lock$ = viewport$
const lock$ = combineLatest([main$, viewport$])
.pipe(
withLatestFrom(adjust$, main$),
map(([{ offset: { y } }, adjust, { offset }]) => (
y >= offset + adjust
)),
map(([{ offset }, { offset: { y } }]) => y >= offset + adjust),
distinctUntilChanged()
)