mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-02 15:13:46 +00:00
Co-authored-by: adamelmore <2363879+adamdottv@users.noreply.github.com> Co-authored-by: David Hill <iamdavidhill@gmail.com>
115 lines
2.9 KiB
TypeScript
115 lines
2.9 KiB
TypeScript
type ReadyWatcher = {
|
|
observer?: MutationObserver
|
|
token: number
|
|
}
|
|
|
|
export function createReadyWatcher(): ReadyWatcher {
|
|
return { token: 0 }
|
|
}
|
|
|
|
export function clearReadyWatcher(state: ReadyWatcher) {
|
|
state.observer?.disconnect()
|
|
state.observer = undefined
|
|
}
|
|
|
|
export function getViewerHost(container: HTMLElement | undefined) {
|
|
if (!container) return
|
|
const host = container.querySelector("diffs-container")
|
|
if (!(host instanceof HTMLElement)) return
|
|
return host
|
|
}
|
|
|
|
export function getViewerRoot(container: HTMLElement | undefined) {
|
|
return getViewerHost(container)?.shadowRoot ?? undefined
|
|
}
|
|
|
|
export function applyViewerScheme(host: HTMLElement | undefined) {
|
|
if (!host) return
|
|
if (typeof document === "undefined") return
|
|
|
|
const scheme = document.documentElement.dataset.colorScheme
|
|
if (scheme === "dark" || scheme === "light") {
|
|
host.dataset.colorScheme = scheme
|
|
return
|
|
}
|
|
|
|
host.removeAttribute("data-color-scheme")
|
|
}
|
|
|
|
export function observeViewerScheme(getHost: () => HTMLElement | undefined) {
|
|
if (typeof document === "undefined") return () => {}
|
|
|
|
applyViewerScheme(getHost())
|
|
if (typeof MutationObserver === "undefined") return () => {}
|
|
|
|
const root = document.documentElement
|
|
const monitor = new MutationObserver(() => applyViewerScheme(getHost()))
|
|
monitor.observe(root, { attributes: true, attributeFilter: ["data-color-scheme"] })
|
|
return () => monitor.disconnect()
|
|
}
|
|
|
|
export function notifyShadowReady(opts: {
|
|
state: ReadyWatcher
|
|
container: HTMLElement
|
|
getRoot: () => ShadowRoot | undefined
|
|
isReady: (root: ShadowRoot) => boolean
|
|
onReady: () => void
|
|
settleFrames?: number
|
|
}) {
|
|
clearReadyWatcher(opts.state)
|
|
opts.state.token += 1
|
|
|
|
const token = opts.state.token
|
|
const settle = Math.max(0, opts.settleFrames ?? 0)
|
|
|
|
const runReady = () => {
|
|
const step = (left: number) => {
|
|
if (token !== opts.state.token) return
|
|
if (left <= 0) {
|
|
opts.onReady()
|
|
return
|
|
}
|
|
requestAnimationFrame(() => step(left - 1))
|
|
}
|
|
|
|
requestAnimationFrame(() => step(settle))
|
|
}
|
|
|
|
const observeRoot = (root: ShadowRoot) => {
|
|
if (opts.isReady(root)) {
|
|
runReady()
|
|
return
|
|
}
|
|
|
|
if (typeof MutationObserver === "undefined") return
|
|
|
|
clearReadyWatcher(opts.state)
|
|
opts.state.observer = new MutationObserver(() => {
|
|
if (token !== opts.state.token) return
|
|
if (!opts.isReady(root)) return
|
|
|
|
clearReadyWatcher(opts.state)
|
|
runReady()
|
|
})
|
|
opts.state.observer.observe(root, { childList: true, subtree: true })
|
|
}
|
|
|
|
const root = opts.getRoot()
|
|
if (!root) {
|
|
if (typeof MutationObserver === "undefined") return
|
|
|
|
opts.state.observer = new MutationObserver(() => {
|
|
if (token !== opts.state.token) return
|
|
|
|
const next = opts.getRoot()
|
|
if (!next) return
|
|
|
|
observeRoot(next)
|
|
})
|
|
opts.state.observer.observe(opts.container, { childList: true, subtree: true })
|
|
return
|
|
}
|
|
|
|
observeRoot(root)
|
|
}
|