mirror of
https://github.com/squidfunk/mkdocs-material.git
synced 2026-07-22 13:53:43 -04:00
Improved rendering of code annotations + keep focus for clipboard button
This commit is contained in:
@@ -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" && (
|
||||
|
||||
@@ -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$
|
||||
|
||||
Reference in New Issue
Block a user