main
ts 39 lines 2.21 KB
Raw
1 // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3 import { state, useSnapState } from './state'
4 import { createElement as h, memo } from 'react'
5 import { SYS_ICONS } from './sysIcons'
6 import { getHFS } from '@hfs/shared'
7
8 const documentComplete = document.readyState === 'complete' ? Promise.resolve()
9 : new Promise(res => document.addEventListener('readystatechange', res))
10 // fonts.ready seems to be unreliable with iphone + additional <script> in custom-html + plugins using frontend_js, but still can be interesting if it resolves faster the document.complete, as we specifically interested in the fonts
11 Promise.race([documentComplete, document.fonts?.ready]).then(async () => {
12 if (!document.fonts)
13 return state.iconsReady = true
14 const fontTester = '9px fontello'
15 await document.fonts.load(fontTester) // force font to be loaded even if we didn't display anything with it yet
16 state.iconsReady = document.fonts.check(fontTester)
17 })
18
19 export interface IconProps { name:string, className?:string, alt?:string, [rest:string]: any }
20 // name = null ? none : unicode ? unicode : "?" ? file_url : font_icon_class
21 export const Icon = memo(({ name, alt, className='', ...props }: IconProps) => {
22 if (!name) return null
23 name = getHFS().icons?.[name] ?? name
24 const [emoji, clazz=name] = SYS_ICONS[name] || []
25 const { iconsReady } = useSnapState()
26 className += ' icon'
27 const nameIsTheIcon = name.length === 1 ||
28 name.match(/^[\uD800-\uDFFF\u2600-\u27BF\u2B00-\u2BFF\u3030-\u303F\u3297\u3299\u00A9\u00AE\u200D\u20E3\uFE0F\u2190-\u21FF\u2300-\u23FF\u2400-\u243F\u25A0-\u25FF\u2600-\u26FF\u2700-\u27BF]*$/)
29 const nameIsUrl = !nameIsTheIcon && /[/?]/.test(name)
30 const isFontIcon = iconsReady && clazz
31 className += nameIsUrl ? ' file-icon' : isFontIcon ? ` font-icon fa-${clazz}` : ' emoji-icon'
32 return h('span',{
33 ...alt ? { 'aria-label': alt } : { 'aria-hidden': true },
34 role: 'img',
35 ...props,
36 ...nameIsUrl ? { style: { backgroundImage: `url(${JSON.stringify(name)})`, ...props?.style } } : undefined,
37 className,
38 }, nameIsTheIcon ? name : isFontIcon ? null : (emoji||'#'))
39 })