mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-16 17:46:17 -08:00
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import type { Cleanup, DisplayConfig, Label, MenuHost, MenuModel, SelectorItem, Valid } from './types'
|
|
import { runCleanups } from './cleanup'
|
|
|
|
export function createMenu<Item extends SelectorItem>(art: MenuHost, name: string, icon: string) {
|
|
let current: object | undefined
|
|
const owned = new Map<'controls' | 'setting', (item: Item) => Label>()
|
|
|
|
function remove(surface: 'controls' | 'setting', callback = owned.get(surface)): void {
|
|
if (!callback || owned.get(surface) !== callback)
|
|
return
|
|
owned.delete(surface)
|
|
const registry = art[surface]
|
|
if (surface === 'controls' && registry.cache?.get && registry.cache.get(name)?.option?.onSelect !== callback)
|
|
return
|
|
if (surface === 'setting' && registry.find && registry.find(name)?.onSelect !== callback)
|
|
return
|
|
registry.remove(name)
|
|
}
|
|
|
|
function clear(): void {
|
|
current = undefined
|
|
runCleanups([...owned].map(([surface, callback]) => () => remove(surface, callback)))
|
|
}
|
|
|
|
function update(config: DisplayConfig, model: MenuModel<Item> | null, active: Valid): void {
|
|
if (!model) {
|
|
clear()
|
|
return
|
|
}
|
|
const state = {}
|
|
current = state
|
|
const valid = () => state === current && active()
|
|
const onSelect = (item: Item): Label => {
|
|
if (!valid())
|
|
return item.html
|
|
model.select(item, valid)
|
|
if (!valid())
|
|
return item.html
|
|
art.notice.show = `${model.title}: ${item.html}`
|
|
if (valid() && config.control)
|
|
art.controls.check(item)
|
|
if (valid() && config.setting)
|
|
art.setting.check(item)
|
|
return item.html
|
|
}
|
|
if (config.control) {
|
|
owned.set('controls', onSelect)
|
|
art.controls.update({ name, position: 'right', html: model.html, style: { padding: '0 10px' }, selector: model.selector, onSelect })
|
|
}
|
|
else {
|
|
remove('controls')
|
|
}
|
|
if (!valid())
|
|
return
|
|
if (config.setting) {
|
|
owned.set('setting', onSelect)
|
|
art.setting.update({ name, tooltip: model.html, html: model.title, icon, width: 200, selector: model.selector, onSelect })
|
|
}
|
|
else {
|
|
remove('setting')
|
|
}
|
|
}
|
|
|
|
function captureNavigation(active: Valid): Cleanup | undefined {
|
|
const setting = art.setting
|
|
const item = setting.find?.(name)
|
|
const callback = owned.get('setting')
|
|
if (!active() || !callback || setting.show !== true || item?.onSelect !== callback || !item.selector || setting.active !== item.selector || typeof setting.render !== 'function')
|
|
return
|
|
return () => {
|
|
if (!active() || art.setting !== setting || setting.show !== true || !setting.option || setting.active !== setting.option)
|
|
return
|
|
const replacement = setting.find?.(name)
|
|
const callback = owned.get('setting')
|
|
if (active() && callback && replacement?.onSelect === callback && replacement.selector)
|
|
setting.render?.(replacement.selector)
|
|
}
|
|
}
|
|
|
|
return { update, clear, captureNavigation }
|
|
}
|