Bilibili-Evolved/registry/lib/components/style/custom-navbar/custom-navbar-item.ts

111 lines
3.4 KiB
TypeScript

import { createPopper, Instance as Popper } from '@popperjs/core'
import { VueModule, Executable } from '@/core/common-types'
import { getComponentSettings, addComponentListener } from '@/core/settings'
import type { CustomNavbarOptions } from '.'
import { getUID } from '@/core/utils'
export const CustomNavbarItems = 'customNavbar.items'
export const CustomNavbarRenderedItems = 'customNavbar.renderedItems'
/**
* 表示自定义顶栏元素的基本信息
*/
export interface CustomNavbarItemInit {
/** 名称 */
name: string
/** 显示名称 */
displayName: string
/** 内容 */
content: Executable<VueModule> | string
/** 设定CSS flex样式 (grow, shrink, basis) */
flexStyle?: string
/** 禁用状态下不响应点击, 也不显示弹窗 */
disabled?: boolean
/** 点击打开的链接 */
href?: string
/** 表示此元素是否代表当前页面, 会增加显示一个底部的边框, 并加粗文本 */
active?: boolean
/** `content`指定的内容mount之后要执行的代码 */
contentMounted?: (item: CustomNavbarItem) => Promise<void> | void
/** 点击运行的代码段 */
clickAction?: Executable
/** 获取或设置提示数字, 将显示在顶部 */
notifyCount?: number
/** 是否在触屏状态下不响应点击 */
touch?: boolean
/** 是否仅在登录后显示 */
loginRequired?: boolean
/** 弹窗内容 */
popupContent?: Executable<VueModule>
/** 设为大于0的值时, 表示预计的弹窗宽度, 将会用于边缘检测, 防止超出viewport */
boundingWidth?: number
/** 不使用默认的弹窗padding */
noPopupPadding?: boolean
/** 是否使用透明的弹窗背景 */
transparentPopup?: boolean
/** 是否懒加载弹窗 */
lazy?: boolean
}
/** 表示自定义顶栏元素 */
export class CustomNavbarItem implements Required<CustomNavbarItemInit> {
name: string
displayName: string
content: Executable<VueModule> | string
flexStyle = '0 0 auto'
disabled = false
href: string = null
active = false
clickAction: Executable = none
contentMounted: (item: CustomNavbarItem) => Promise<void> | void = none
notifyCount = 0
touch = false
loginRequired = false
popupContent: Executable<VueModule> = null
popper: Popper = null
boundingWidth = 0
noPopupPadding = false
transparentPopup = false
lazy = true
hidden = false
order = 0
requestedPopup: boolean
static navbarOptions = getComponentSettings('customNavbar').options as CustomNavbarOptions
constructor(init: CustomNavbarItemInit) {
Object.assign(this, init)
if (!this.name) {
throw new Error('Missing CustomNavbarItem name')
}
if (this.content === undefined) {
throw new Error('Missing CustomNavbarItem content')
}
addComponentListener(
'customNavbar.touch',
(value: boolean) => {
this.touch = value ? init.touch : false
},
true,
)
this.hidden =
CustomNavbarItem.navbarOptions.hidden.includes(this.name) || (!getUID() && init.loginRequired)
const orderMap = CustomNavbarItem.navbarOptions.order
this.order = orderMap[this.name] || 0
this.requestedPopup = !this.lazy
}
get element() {
return dq(`.custom-navbar-item[data-name='${this.name}']`) as HTMLElement
}
toString() {
return this.name
}
usePopper(container: HTMLElement, popup: HTMLElement) {
this.popper = createPopper(container, popup, { placement: 'bottom' })
}
}