mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-04 17:45:41 +03:00
b834d4c4ee
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
127 lines
2.9 KiB
TypeScript
127 lines
2.9 KiB
TypeScript
import { getContext, onDestroy, setContext } from 'svelte'
|
|
|
|
/**
|
|
* @public
|
|
*/
|
|
export interface FocusManager {
|
|
next: (inc?: 1 | -1) => void
|
|
setFocus: (idx: number) => void
|
|
setFocusPos: (order: number) => void
|
|
updateFocus: (idx: number, order: number) => void
|
|
|
|
// Check if current manager has focus
|
|
hasFocus: () => boolean
|
|
}
|
|
|
|
class FocusManagerImpl implements FocusManager {
|
|
counter = 0
|
|
elements: Array<{
|
|
id: number
|
|
order: number
|
|
focus: () => boolean
|
|
isFocus: () => boolean
|
|
}> = []
|
|
|
|
current = 0
|
|
register (order: number, focus: () => boolean, isFocus: () => boolean): number {
|
|
const el = { id: this.counter++, order, focus, isFocus }
|
|
this.elements.push(el)
|
|
this.sort()
|
|
return el.id
|
|
}
|
|
|
|
unregister (idx: number): void {
|
|
this.elements = this.elements.filter((it) => it.id !== idx)
|
|
this.sort()
|
|
}
|
|
|
|
sort (): void {
|
|
// this.needSort = 0
|
|
this.elements.sort((a, b) => {
|
|
return a.order - b.order
|
|
})
|
|
}
|
|
|
|
next (inc?: 1 | -1): void {
|
|
while (true) {
|
|
this.current = this.current + (inc ?? 1)
|
|
if (this.elements[Math.abs(this.current) % this.elements.length].focus()) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
setFocus (idx: number): void {
|
|
this.current = this.elements.findIndex((it) => it.id === idx) ?? 0
|
|
this.elements[Math.abs(this.current) % this.elements.length].focus()
|
|
}
|
|
|
|
setFocusPos (order: number): void {
|
|
const idx = this.elements.findIndex((it) => it.order === order)
|
|
if (idx !== undefined) {
|
|
this.current = idx
|
|
this.elements[Math.abs(this.current) % this.elements.length].focus()
|
|
}
|
|
}
|
|
|
|
updateFocus (idx: number, order: number): void {
|
|
const el = this.elements.find((it) => it.id === idx)
|
|
if (el !== undefined) {
|
|
if (el.order !== order) {
|
|
el.order = order
|
|
this.sort()
|
|
}
|
|
}
|
|
}
|
|
|
|
hasFocus (): boolean {
|
|
for (const el of this.elements) {
|
|
if (el.isFocus()) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @public
|
|
*/
|
|
export function createFocusManager (): FocusManager {
|
|
const mgr = new FocusManagerImpl()
|
|
setFocusManager(mgr)
|
|
return mgr
|
|
}
|
|
|
|
export function setFocusManager (manager: FocusManager): void {
|
|
setContext('ui.focus.elements', manager)
|
|
}
|
|
|
|
/**
|
|
* @public
|
|
*/
|
|
export function getFocusManager (): FocusManager | undefined {
|
|
return getContext('ui.focus.elements')
|
|
}
|
|
|
|
/**
|
|
* Register new focus reciever if order !== -1
|
|
* @public
|
|
*/
|
|
export function registerFocus (
|
|
order: number,
|
|
item: { focus: () => boolean, isFocus: () => boolean }
|
|
): { idx: number, focusManager?: FocusManager } {
|
|
const focusManager = getFocusManager() as FocusManagerImpl
|
|
if (order === -1) {
|
|
return { idx: -1, focusManager }
|
|
}
|
|
const idx = focusManager?.register(order, item.focus, item.isFocus) ?? -1
|
|
if (idx !== -1) {
|
|
onDestroy(() => {
|
|
focusManager.unregister(idx)
|
|
})
|
|
}
|
|
return { idx, focusManager }
|
|
}
|