Added more inline comments and simplified component mounting

This commit is contained in:
squidfunk
2021-02-13 17:03:15 +01:00
parent 96797b471f
commit aacb5ca5a7
45 changed files with 155 additions and 84 deletions

View File

@@ -20,6 +20,8 @@
* IN THE SOFTWARE.
*/
import { getElementOrThrow, getElements } from "~/browser"
/* ----------------------------------------------------------------------------
* Types
* ------------------------------------------------------------------------- */
@@ -31,12 +33,14 @@ export type ComponentType =
| "announce" /* Announcement bar */
| "container" /* Container */
| "content" /* Content */
| "dialog" /* Dialog */
| "header" /* Header */
| "header-title" /* Header title */
| "main" /* Main area */
| "search" /* Search */
| "search-query" /* Search input */
| "search-result" /* Search results */
| "sidebar" /* Sidebar */
| "skip" /* Skip link */
| "source" /* Repository information */
| "tabs" /* Navigation tabs */
@@ -55,3 +59,39 @@ export type Component<
T & {
ref: U /* Component reference */
}
/* ----------------------------------------------------------------------------
* Functions
* ------------------------------------------------------------------------- */
/**
* Retrieve the element for a given component or throw a reference error
*
* @template T - Element type
*
* @param type - Component type
* @param node - Node of reference
*
* @returns Element
*/
export function getComponentElement<T extends HTMLElement>(
type: ComponentType, node: ParentNode = document
): T {
return getElementOrThrow(`[data-md-component=${type}]`, node)
}
/**
* Retrieve all elements for a given component
*
* @template T - Element type
*
* @param type - Component type
* @param node - Node of reference
*
* @returns Elements
*/
export function getComponentElements<T extends HTMLElement>(
type: ComponentType, node: ParentNode = document
): T[] {
return getElements(`[data-md-component=${type}]`, node)
}

View File

@@ -61,6 +61,9 @@ interface MountOptions {
/**
* Mount content
*
* This function mounts all components that are found in the content of the
* actual article, including code blocks, data tables and details.
*
* @param el - Content element
* @param options - Options
*

View File

@@ -111,8 +111,8 @@ export function watchCodeBlock(
/**
* Mount code block
*
* This function ensures that overflowing code blocks are focusable by keyboard,
* so they can be scrolled without a mouse to improve on accessibility.
* This function ensures that an overflowing code block is focusable through
* keyboard, so it can be scrolled without a mouse to improve on accessibility.
*
* @param el - Code block element
* @param options - Options

View File

@@ -88,8 +88,8 @@ export function watchDetails(
/**
* Mount details
*
* This function ensures that `details` tags are opened prior to printing, so
* the whole content of the page is included and on anchor jumps.
* This function ensures that `details` tags are opened on anchor jumps and
* prior to printing, so the whole content of the page is visible.
*
* @param el - Details element
* @param options - Options

View File

@@ -52,6 +52,9 @@ const sentinel = createElement("table")
/**
* Mount data table
*
* This function wraps a data table in another scrollable container, so they
* can be scrolled on smaller screen sizes and won't break the layout.
*
* @param el - Data table element
*
* @returns Data table component observable

View File

@@ -105,6 +105,9 @@ export function watchDialog(
/**
* Mount dialog
*
* This function makes the dialog in the right corner appear when a new alert
* is emitted through the subject that is passed as part of the options.
*
* @param el - Dialog element
* @param options - Options
*

View File

@@ -34,12 +34,15 @@ import {
combineLatestWith,
distinctUntilChanged,
distinctUntilKeyChanged,
endWith,
filter,
finalize,
map,
observeOn,
shareReplay,
startWith,
switchMap
switchMap,
tap
} from "rxjs/operators"
import { feature } from "~/_"
@@ -118,7 +121,7 @@ function isHidden({ viewport$ }: WatchOptions): Observable<boolean> {
.pipe(
filter(([{ offset }, [, y]]) => Math.abs(y - offset.y) > 100),
map(([, [direction]]) => direction),
distinctUntilChanged(),
distinctUntilChanged()
)
/* Compute threshold for autohiding */
@@ -127,7 +130,7 @@ function isHidden({ viewport$ }: WatchOptions): Observable<boolean> {
.pipe(
map(([{ offset }, search]) => offset.y > 400 && !search),
distinctUntilChanged(),
switchMap(active => active ? hidden$ : NEVER),
switchMap(active => active ? hidden$ : of(false)),
startWith(false)
)
}
@@ -173,10 +176,8 @@ export function watchHeader(
/**
* Mount header
*
* The header must be connected to the main area observable outside of the
* operator function, as the header will persist in-between document switches
* while the main area is replaced. However, the header observable must be
* passed to this function, so we connect both via a long-living subject.
* This function manages the different states of the header, i.e. whether it's
* hidden or rendered with a shadow. This depends heavily on the main area.
*
* @param el - Header element
* @param options - Options

View File

@@ -20,7 +20,12 @@
* IN THE SOFTWARE.
*/
import { NEVER, Observable, Subject, animationFrameScheduler } from "rxjs"
import {
NEVER,
Observable,
Subject,
animationFrameScheduler
} from "rxjs"
import {
distinctUntilKeyChanged,
finalize,
@@ -104,6 +109,9 @@ export function watchHeaderTitle(
/**
* Mount header title
*
* This function swaps the header title from the site title to the title of the
* current page when the user scrolls past the first headline.
*
* @param el - Header title element
* @param options - Options
*

View File

@@ -27,7 +27,6 @@ import { configuration } from "~/_"
import {
Keyboard,
getActiveElement,
getElementOrThrow,
getElements,
requestJSON,
setElementFocus,
@@ -41,7 +40,7 @@ import {
setupSearchWorker
} from "~/integrations"
import { Component } from "../../_"
import { Component, getComponentElement } from "../../_"
import { SearchQuery, mountSearchQuery } from "../query"
import { SearchResult, mountSearchResult } from "../result"
@@ -89,6 +88,9 @@ function fetchSearchIndex(url: string) {
/**
* Mount search
*
* This function sets up the search functionality, including the underlying
* web worker and all keyboard bindings.
*
* @param el - Search element
* @param options - Options
*
@@ -103,8 +105,8 @@ export function mountSearch(
))
/* Retrieve elements */
const query = getElementOrThrow("[data-md-component=search-query]", el)
const result = getElementOrThrow("[data-md-component=search-result]", el)
const query = getComponentElement("search-query", el)
const result = getComponentElement("search-result", el)
/* Re-emit query when search is ready */
const { tx$, rx$ } = worker

View File

@@ -64,6 +64,9 @@ let fetch$: Observable<Source>
/**
* Watch repository information
*
* This function will try to read the repository facts from session storage,
* and if unsuccessful, fetch them from the underlying provider.
*
* @param el - Repository information element
*
* @returns Repository information observable

View File

@@ -95,6 +95,9 @@ export function watchTabs(
/**
* Mount navigation tabs
*
* This function hides the navigation tabs when scrolling past the threshold
* and makes them reappear in a nice CSS animation when scrolling back up.
*
* @param el - Navigation tabs element
* @param options - Options
*