Improved rendering of code annotations + keep focus for clipboard button

This commit is contained in:
squidfunk
2021-12-04 11:33:21 +01:00
parent 122be2ec46
commit fb751c108c
18 changed files with 92 additions and 130 deletions

View File

@@ -33,8 +33,7 @@ import {
switchMap,
takeLast,
takeUntil,
tap,
withLatestFrom
tap
} from "rxjs"
import { feature } from "~/_"
@@ -69,7 +68,6 @@ export interface CodeBlock {
* Mount options
*/
interface MountOptions {
hover$: Observable<boolean> /* Media hover observable */
print$: Observable<boolean> /* Media print observable */
}
@@ -87,13 +85,13 @@ let sequence = 0
* ------------------------------------------------------------------------- */
/**
* Find the code annotations belonging to a code block
* Find candidate list element directly following a code block
*
* @param el - Code block element
*
* @returns Code annotation list or nothing
* @returns List element or nothing
*/
function findAnnotationList(el: HTMLElement): HTMLElement | undefined {
function findCandidateList(el: HTMLElement): HTMLElement | undefined {
if (el.nextElementSibling) {
const sibling = el.nextElementSibling as HTMLElement
if (sibling.tagName === "OL")
@@ -101,7 +99,7 @@ function findAnnotationList(el: HTMLElement): HTMLElement | undefined {
/* Skip empty paragraphs - see https://bit.ly/3r4ZJ2O */
else if (sibling.tagName === "P" && !sibling.children.length)
return findAnnotationList(sibling)
return findCandidateList(sibling)
}
/* Everything else */
@@ -151,20 +149,17 @@ export function watchCodeBlock(
* @returns Code block and annotation component observable
*/
export function mountCodeBlock(
el: HTMLElement, { hover$, ...options }: MountOptions
el: HTMLElement, options: MountOptions
): Observable<Component<CodeBlock | Annotation>> {
const { matches: hover } = matchMedia("(hover)")
return defer(() => {
const push$ = new Subject<CodeBlock>()
push$
.pipe(
withLatestFrom(hover$)
)
.subscribe(([{ scrollable: scroll }, hover]) => {
if (scroll && hover)
el.setAttribute("tabindex", "0")
else
el.removeAttribute("tabindex")
})
push$.subscribe(({ scrollable }) => {
if (scrollable && hover)
el.setAttribute("tabindex", "0")
else
el.removeAttribute("tabindex")
})
/* Render button for Clipboard.js integration */
if (ClipboardJS.isSupported()) {
@@ -177,11 +172,12 @@ export function mountCodeBlock(
}
/* Handle code annotations */
const container =
el.closest(".highlighttable") ||
el.closest(".highlight")
const container = el.closest([
":not(td.code) > .highlight", /* Code blocks */
".highlighttable" /* Code blocks with line numbers */
].join(", "))
if (container instanceof HTMLElement) {
const list = findAnnotationList(container)
const list = findCandidateList(container)
/* Mount code annotations, if enabled */
if (typeof list !== "undefined" && (

View File

@@ -31,12 +31,14 @@ import {
map,
switchMap,
take,
tap
tap,
throttleTime
} from "rxjs"
import {
ElementOffset,
getElement,
getElementSize,
watchElementContentOffset,
watchElementFocus,
watchElementOffset
@@ -76,10 +78,13 @@ export function watchAnnotation(
watchElementContentOffset(container)
]))
.pipe(
map(([{ x, y }, scroll]) => ({
x: x - scroll.x,
y: y - scroll.y
}))
map(([{ x, y }, scroll]) => {
const { width } = getElementSize(el)
return ({
x: x - scroll.x + width / 2,
y: y - scroll.y
})
})
)
/* Actively watch code annotation on focus */
@@ -122,7 +127,18 @@ export function mountAnnotation(
}
})
/* Blur open annotation on click (= close) */
/* Track relative origin of tooltip */
push$
.pipe(
throttleTime(500),
map(() => container.getBoundingClientRect()),
map(({ x }) => x)
)
.subscribe(origin => {
el.style.setProperty("--md-tooltip-0", `${-origin}px`)
})
/* Close open annotation on click */
const index = getElement(":scope > :last-child", el)
const blur$ = fromEvent(index, "mousedown", { once: true })
push$