semaphore/src/routes/_components/FocusRestoration.html

91 lines
2.4 KiB
HTML

<div
on:focusin="saveFocus(event)"
on:focusout="clearFocus()"
>
<slot></slot>
</div>
<script>
import { PAGE_HISTORY_SIZE } from '../_static/pages'
import { QuickLRU } from '../_thirdparty/quick-lru/quick-lru'
import { tryToFocusElement } from '../_utils/tryToFocusElement'
const cache = new QuickLRU({ maxSize: PAGE_HISTORY_SIZE })
if (process.browser) {
window.__focusRestorationCache = cache
}
export default {
oncreate () {
this.setupPushState()
this.restoreFocus()
if (process.env.NODE_ENV !== 'production') {
if (!this.get().realm) {
throw new Error('FocusRestoration needs a realm')
}
}
},
ondestroy () {
this.teardownPushState()
},
methods: {
setupPushState () {
this.onPushState = this.onPushState.bind(this)
this.setInCache({ ignoreBlurEvents: false })
window.addEventListener('pushState', this.onPushState)
},
teardownPushState () {
window.removeEventListener('pushState', this.onPushState)
},
setInCache (obj) {
const { realm } = this.get()
if (!cache.has(realm)) {
cache.set(realm, {})
}
Object.assign(cache.get(realm), obj)
},
deleteInCache (key) {
const { realm } = this.get()
if (cache.has(realm)) {
delete cache.get(realm)[key]
}
},
getInCache () {
const { realm } = this.get()
return cache.get(realm) || {}
},
onPushState () {
this.setInCache({ ignoreBlurEvents: true })
},
restoreFocus () {
const { realm } = this.get()
const { elementId } = this.getInCache()
if (!elementId) {
return
}
console.log('restoreFocus', realm, elementId)
tryToFocusElement(elementId)
},
clearFocus () {
const { realm } = this.get()
const { ignoreBlurEvents } = this.getInCache()
if (!ignoreBlurEvents) {
console.log('clearFocus', realm)
this.deleteInCache('elementId')
}
},
saveFocus (e) {
const { realm } = this.get()
const element = e.target
if (element) {
const elementId = element.getAttribute('id')
if (elementId) {
console.log('saveFocus', realm, elementId)
this.setInCache({ elementId })
}
}
}
}
}
</script>