main
vue 59 lines 1.76 KB
Raw
1 <template>
2 <component :is="componentName" v-bind="options">
3 <template v-if="$slots.default">
4 <slot />
5 </template>
6 <template v-else>
7 <Icon v-if="icon" :icon :width="options.size || undefined" :height="options.size || undefined" />
8 </template>
9 </component>
10 </template>
11
12 <script setup lang="ts">
13 import type { IconifyIcon } from "@iconify/vue"
14 import { Icon, loadIcon } from "@iconify/vue"
15 import { NIcon, NIconWrapper } from "naive-ui"
16 import { computed, ref, watchEffect } from "vue"
17
18 const props = defineProps<{
19 name?: string
20 size?: number
21 bgSize?: number
22 color?: string
23 bgColor?: string
24 borderRadius?: number
25 depth?: 1 | 2 | 3 | 4 | 5
26 }>()
27
28 const useWrapper = computed(() => !!(props.bgColor || props.bgSize || props.borderRadius))
29 const componentName = computed(() => (useWrapper.value ? NIconWrapper : NIcon))
30
31 const options = computed(() => {
32 const opt: Partial<{ size: number; color: string; borderRadius: number; iconColor: string; depth: number }> = {}
33 if (useWrapper.value) {
34 if (props.bgSize !== undefined) opt.size = props.bgSize
35 if (props.bgColor !== undefined) opt.color = props.bgColor
36 if (props.borderRadius !== undefined) opt.borderRadius = props.borderRadius
37 if (props.color !== undefined) opt.iconColor = props.color
38 } else {
39 if (props.color !== undefined) opt.color = props.color
40 if (props.depth !== undefined) opt.depth = props.depth
41 if (props.size !== undefined) opt.size = props.size
42 }
43 return opt
44 })
45
46 const load = (name: string) => loadIcon(name).catch(() => console.error(`Failed to load icon ${name}`))
47
48 const icon = ref<void | Required<IconifyIcon>>()
49
50 function setIcon(name: string | undefined) {
51 if (name) {
52 load(name).then(res => (icon.value = res))
53 }
54 }
55
56 setIcon(props.name)
57
58 watchEffect(() => setIcon(props.name))
59 </script>