| 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 | }) |