Restructued UI observables

This commit is contained in:
squidfunk 2019-10-27 10:26:54 +01:00
parent a633f4fec7
commit 85a18c64fa
9 changed files with 237 additions and 14 deletions

73
package-lock.json generated
View File

@ -374,6 +374,12 @@
"integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==",
"dev": true
},
"@types/escape-html": {
"version": "0.0.20",
"resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-0.0.20.tgz",
"integrity": "sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==",
"dev": true
},
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@ -391,6 +397,18 @@
"@types/node": "*"
}
},
"@types/lunr": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.3.2.tgz",
"integrity": "sha512-zcUZYquYDUEegRRPQtkZ068U9CoIjW6pJMYCVDRK25r76FEWvMm1oHqZQUfQh4ayIZ42lipXOpXEiAtGXc1XUg==",
"dev": true
},
"@types/lz-string": {
"version": "1.3.33",
"resolved": "https://registry.npmjs.org/@types/lz-string/-/lz-string-1.3.33.tgz",
"integrity": "sha512-yWj3OnlKlwNpq9+Jh/nJkVAD3ta8Abk2kIRpjWpVkDlAD43tn6Q6xk5hurp84ndcq54jBDBGCD/WcIR0pspG0A==",
"dev": true
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@ -409,6 +427,15 @@
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
"dev": true
},
"@types/ramda": {
"version": "0.26.26",
"resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.26.26.tgz",
"integrity": "sha512-jDx2Lp2WvziMTcDxOU21yzRr6jP/VTWvpg6SQxeM63VldSjugUY1N9p1Q8YY/wpGvqzpkstUFmg2oGJdBSp5gg==",
"dev": true,
"requires": {
"ts-toolbelt": "^4.7.7"
}
},
"@types/source-list-map": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
@ -2516,6 +2543,11 @@
"is-symbol": "^1.0.2"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@ -4886,6 +4918,11 @@
"resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.1.0.tgz",
"integrity": "sha512-53pTQX8jkjZBWSPJa/+3UJyIPcGmeWWwqS4RRr5GxhRilqL9tv/Vuj7Vb1Nz3Dtz2HTK2Pdmrf3zevHS/ZycjQ=="
},
"lz-string": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
"integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY="
},
"make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
@ -6530,10 +6567,10 @@
"integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
"dev": true
},
"rambda": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/rambda/-/rambda-3.1.0.tgz",
"integrity": "sha512-J9mLLbZabxjr5h1UrT0e6AIen7Ri5XqyUAEMs+8ceVbgp2WLaCqizmiwHjZdpkKTFjctjh/QHB9bxwB6F1LTwA=="
"ramda": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
"integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ=="
},
"randomatic": {
"version": "3.1.1",
@ -8675,6 +8712,12 @@
}
}
},
"ts-toolbelt": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-4.8.3.tgz",
"integrity": "sha512-qSC/t6vfUPqVMkH7wQmRwYbShubAJufUoUynJj8e+AlSXK3+M6rC/OnQ+Mdw6Qd/WYTf46QZDM8nUhxYVJTIPw==",
"dev": true
},
"tslib": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
@ -9443,6 +9486,28 @@
"errno": "~0.1.7"
}
},
"worker-loader": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz",
"integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==",
"dev": true,
"requires": {
"loader-utils": "^1.0.0",
"schema-utils": "^0.4.0"
},
"dependencies": {
"schema-utils": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
"integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
"dev": true,
"requires": {
"ajv": "^6.1.0",
"ajv-keywords": "^3.1.0"
}
}
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",

View File

@ -30,14 +30,20 @@
},
"dependencies": {
"clipboard": "^2.0.0",
"escape-html": "^1.0.3",
"js-cookie": "^2.2.1",
"lunr": "^2.3.6",
"lunr-languages": "^1.1.0",
"rambda": "^3.1.0",
"lz-string": "^1.4.4",
"ramda": "^0.26.1",
"rxjs": "^6.5.3"
},
"devDependencies": {
"@types/escape-html": "0.0.20",
"@types/lunr": "^2.3.2",
"@types/lz-string": "^1.3.33",
"@types/node": "^12.7.8",
"@types/ramda": "^0.26.26",
"@types/webpack": "^4.39.2",
"autoprefixer": "^9.6.1",
"css-mqpacker": "^7.0.0",
@ -60,10 +66,11 @@
"tslint-sonarts": "^1.9.0",
"typescript": "^3.6.3",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9"
"webpack-cli": "^3.3.9",
"worker-loader": "^2.0.0"
},
"engines": {
"node": ">= 8"
"node": ">= 10"
},
"private": true
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016-2019 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
import { OperatorFunction, pipe } from "rxjs"
import { filter, map } from "rxjs/operators"
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Retrieve an element matching the query selector
*
* @template T - Element type
*
* @param selector - Query selector
*
* @return HTML element
*/
export function getElement<T extends HTMLElement>(
selector: string
): T | undefined {
return document.querySelector<T>(selector) || undefined
}
/* ------------------------------------------------------------------------- */
/**
* Retrieve an element matching the query selector
*
* @template T - Element type
*
* @return HTML element observable
*/
export function withElement<
T extends HTMLElement
>(): OperatorFunction<string, T> {
return pipe(
map(selector => getElement<T>(selector)!),
filter<T>(Boolean)
)
}

View File

@ -20,6 +20,6 @@
* IN THE SOFTWARE.
*/
/* ----------------------------------------------------------------------------
* Types
* ------------------------------------------------------------------------- */
export * from "./element"
export * from "./location"
export * from "./viewport"

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016-2019 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
import { Observable, fromEvent } from "rxjs"
import { filter, map, startWith } from "rxjs/operators"
/* ----------------------------------------------------------------------------
* Data
* ------------------------------------------------------------------------- */
/**
* Observable for window hash changes
*/
const hash$ = fromEvent<HashChangeEvent>(window, "hashchange")
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Create an observable emitting changes in location hashes
*
* @return Hash change observable
*/
export function fromLocationHash(): Observable<string> {
return hash$.pipe(
startWith(document.location.hash),
map(() => document.location.hash),
filter(hash => hash.length > 0)
)
}

View File

@ -20,7 +20,7 @@
* IN THE SOFTWARE.
*/
import { equals } from "rambda"
import { equals } from "ramda"
import { Observable, fromEvent, merge } from "rxjs"
import { distinctUntilChanged, map, startWith } from "rxjs/operators"
@ -93,7 +93,7 @@ export function getViewportSize(): ViewportSize {
*
* @return Viewport offset observable
*/
export function watchViewportOffset(): Observable<ViewportOffset> {
export function fromViewportOffset(): Observable<ViewportOffset> {
return merge(scroll$, resize$).pipe(
map(getViewportOffset),
startWith(getViewportOffset()),
@ -106,7 +106,7 @@ export function watchViewportOffset(): Observable<ViewportOffset> {
*
* @return Viewport size observable
*/
export function watchViewportSize(): Observable<ViewportSize> {
export function fromViewportSize(): Observable<ViewportSize> {
return resize$.pipe(
map(getViewportSize),
startWith(getViewportSize()),

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016-2019 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Convert a HTML collection to an array
*
* @template T - HTML element type
*
* @param collection - HTML collection
*
* @return Array of HTML elements
*/
export function toArray<
T extends HTMLElement
>(collection: HTMLCollection): T[] {
return Array.from(collection) as T[]
}