@bagelink/vue 1.4.103 → 1.4.105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { IconType } from '@bagelink/vue'
|
|
3
|
+
import { useDevice } from '@bagelink/vue'
|
|
4
|
+
import { ref, onMounted, watchEffect } from 'vue'
|
|
3
5
|
import { FONT_AWESOME_ICONS, MATERIAL_ICONS, FONT_AWESOME_BRANDS_ICONS } from './constants'
|
|
4
|
-
import { ref, onMounted, onUnmounted } from 'vue'
|
|
5
6
|
|
|
6
7
|
const props = withDefaults(defineProps<{
|
|
7
8
|
icon?: IconType
|
|
@@ -17,22 +18,9 @@ const props = withDefaults(defineProps<{
|
|
|
17
18
|
size: 1
|
|
18
19
|
})
|
|
19
20
|
|
|
20
|
-
const iconRender = $computed(() => props.icon
|
|
21
|
+
const iconRender = $computed(() => (props.icon ?? props.name) as IconType)
|
|
21
22
|
|
|
22
|
-
const isMobile =
|
|
23
|
-
|
|
24
|
-
const checkMobile = () => {
|
|
25
|
-
isMobile.value = window.innerWidth <= 910
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
onMounted(() => {
|
|
29
|
-
checkMobile()
|
|
30
|
-
window.addEventListener('resize', checkMobile)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
onUnmounted(() => {
|
|
34
|
-
window.removeEventListener('resize', checkMobile)
|
|
35
|
-
})
|
|
23
|
+
const { isMobile } = useDevice()
|
|
36
24
|
|
|
37
25
|
const computedSize = $computed(() => {
|
|
38
26
|
if (isMobile.value && props.mobileSize !== undefined) {
|
|
@@ -49,36 +37,108 @@ const iconRenderType = $computed(() => {
|
|
|
49
37
|
})
|
|
50
38
|
|
|
51
39
|
const isFaBrand = $computed(() => FONT_AWESOME_BRANDS_ICONS.includes(iconRender))
|
|
40
|
+
|
|
41
|
+
// Hide until required font is ready to avoid ligature text/fallback flash
|
|
42
|
+
const isMaterialReady = ref(true)
|
|
43
|
+
const isFAFreeReady = ref(true)
|
|
44
|
+
const isFABrandsReady = ref(true)
|
|
45
|
+
|
|
46
|
+
function getFontFaceSet(): FontFaceSet | null {
|
|
47
|
+
if (typeof document === 'undefined') return null
|
|
48
|
+
const maybeFonts = (document as unknown as { fonts?: FontFaceSet }).fonts
|
|
49
|
+
return maybeFonts ?? null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function supportsFontLoading(): boolean {
|
|
53
|
+
const fonts = getFontFaceSet()
|
|
54
|
+
return fonts !== null && typeof fonts.load === 'function'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function ensureFontLoaded(family: string): Promise<boolean> {
|
|
58
|
+
if (!supportsFontLoading()) return true
|
|
59
|
+
try {
|
|
60
|
+
const fonts = getFontFaceSet()
|
|
61
|
+
if (!fonts) return true
|
|
62
|
+
if (fonts.check(`1em "${family}"`)) return true
|
|
63
|
+
await fonts.load(`1em "${family}"`)
|
|
64
|
+
return fonts.check(`1em "${family}"`)
|
|
65
|
+
} catch {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function loadMaterialIfNeeded() {
|
|
71
|
+
const ok = await ensureFontLoaded('Material Symbols Outlined')
|
|
72
|
+
isMaterialReady.value = ok
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function loadFAFreeIfNeeded() {
|
|
76
|
+
const ok = await ensureFontLoaded('Font Awesome 6 Free')
|
|
77
|
+
isFAFreeReady.value = ok
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function loadFABrandsIfNeeded() {
|
|
81
|
+
const ok = await ensureFontLoaded('Font Awesome 6 Brands')
|
|
82
|
+
isFABrandsReady.value = ok
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
onMounted(() => {
|
|
86
|
+
if (!supportsFontLoading()) return
|
|
87
|
+
if (iconRenderType === 'material') {
|
|
88
|
+
const fonts = getFontFaceSet()
|
|
89
|
+
isMaterialReady.value = fonts ? fonts.check('1em "Material Symbols Outlined"') : true
|
|
90
|
+
void loadMaterialIfNeeded()
|
|
91
|
+
} else if (isFaBrand) {
|
|
92
|
+
const fonts = getFontFaceSet()
|
|
93
|
+
isFABrandsReady.value = fonts ? fonts.check('1em "Font Awesome 6 Brands"') : true
|
|
94
|
+
void loadFABrandsIfNeeded()
|
|
95
|
+
} else {
|
|
96
|
+
const fonts = getFontFaceSet()
|
|
97
|
+
isFAFreeReady.value = fonts ? fonts.check('1em "Font Awesome 6 Free"') : true
|
|
98
|
+
void loadFAFreeIfNeeded()
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
watchEffect(() => {
|
|
103
|
+
if (!supportsFontLoading()) return
|
|
104
|
+
if (iconRenderType === 'material') {
|
|
105
|
+
void loadMaterialIfNeeded()
|
|
106
|
+
} else if (isFaBrand) {
|
|
107
|
+
void loadFABrandsIfNeeded()
|
|
108
|
+
} else {
|
|
109
|
+
void loadFAFreeIfNeeded()
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const isCurrentFontReady = $computed(() => {
|
|
114
|
+
if (iconRenderType === 'material') return isMaterialReady.value
|
|
115
|
+
return isFaBrand ? isFABrandsReady.value : isFAFreeReady.value
|
|
116
|
+
})
|
|
52
117
|
</script>
|
|
53
118
|
|
|
54
119
|
<template>
|
|
55
120
|
<span
|
|
56
|
-
v-if="iconRenderType === 'material'"
|
|
57
|
-
class="
|
|
58
|
-
:class="{ 'round flex aspect-ratio-1 justify-content-center': round }"
|
|
59
|
-
:style="{
|
|
121
|
+
v-if="iconRenderType === 'material'" class="bgl_icon-font notranslate"
|
|
122
|
+
:class="{ 'round flex aspect-ratio-1 justify-content-center': round }" :style="{
|
|
60
123
|
'fontSize': `${computedSize}rem`,
|
|
61
124
|
color,
|
|
62
125
|
'font-variation-settings': `'FILL' ${fill ? 1 : 0}, 'wght' ${weight || 400}`,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
translate="no"
|
|
126
|
+
'width': round ? `calc(${computedSize}rem * 2)` : 'auto',
|
|
127
|
+
'height': round ? `calc(${computedSize}rem * 2)` : 'auto',
|
|
128
|
+
'visibility': isCurrentFontReady ? 'visible' : 'hidden',
|
|
129
|
+
}" translate="no"
|
|
67
130
|
>
|
|
68
131
|
{{ iconRender }}
|
|
69
132
|
</span>
|
|
70
133
|
<span
|
|
71
|
-
v-else-if="iconRenderType === 'font-awesome'"
|
|
72
|
-
class="fa bgl_icon-font notranslate"
|
|
73
|
-
:class="[
|
|
134
|
+
v-else-if="iconRenderType === 'font-awesome'" class="fa bgl_icon-font notranslate" :class="[
|
|
74
135
|
`fa-${iconRender}`,
|
|
75
136
|
{
|
|
76
137
|
'fa-brands': isFaBrand,
|
|
77
138
|
'fa-solid': fill,
|
|
78
139
|
'far': !fill && !isFaBrand,
|
|
79
140
|
},
|
|
80
|
-
]"
|
|
81
|
-
:style="{ 'fontSize': `${computedSize}rem`, color, 'font-variation-settings': `'wght' ${weight || 400}` }"
|
|
141
|
+
]" :style="{ 'fontSize': `${computedSize}rem`, color, 'font-variation-settings': `'wght' ${weight || 400}`, 'visibility': isCurrentFontReady ? 'visible' : 'hidden' }"
|
|
82
142
|
translate="no"
|
|
83
143
|
/>
|
|
84
144
|
</template>
|
|
@@ -86,6 +146,7 @@ const isFaBrand = $computed(() => FONT_AWESOME_BRANDS_ICONS.includes(iconRender)
|
|
|
86
146
|
<style>
|
|
87
147
|
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');
|
|
88
148
|
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css');
|
|
149
|
+
|
|
89
150
|
[dir='rtl'] .data-row .bgl_icon-font,
|
|
90
151
|
[dir='rtl'] .embedded-field .bgl_icon-font,
|
|
91
152
|
[dir='rtl'] .rich-text-editor .toolbar .bgl_icon-font {
|