// Icons import { aliases, mdi } from '@/iconsets/mdi' // Utilities import { computed, inject, unref } from 'vue' import { defineComponent, genericComponent, mergeDeep, propsFactory, } from '@/utils' // Types import type { InjectionKey, JSXComponent, PropType, Ref } from 'vue' import ColorName from '@/types/colors' import { getNextColor } from '@/utils/useColors' import { makeComponentProps } from '@/composables/component' export type IconValue = | string | (string | [path: string, opacity: number])[] | JSXComponent export const IconValue = [ String, Function, Object, Array, ] as PropType export interface IconAliases { [name: string]: IconValue } export interface IconProps { tag: string icon?: IconValue disabled?: boolean } type IconComponent = JSXComponent export interface IconSet { component: IconComponent } export type IconOptions = { defaultSet?: string aliases?: Partial sets?: Record } type IconInstance = { component: IconComponent icon?: IconValue } export const IconSymbol: InjectionKey> = Symbol.for('untitled:icons') export const makeIconProps = propsFactory( { icon: { type: IconValue, }, // Could not remove this and use makeTagProps, types complained because it is not required tag: { type: String, required: true, }, ...makeComponentProps(), }, 'icon' ) export const UComponentIcon = genericComponent()({ name: 'UComponentIcon', props: makeIconProps(), setup(props, { slots }) { return () => { const Icon = props.icon as JSXComponent return {props.icon ? : slots.default?.()} } }, }) export type VComponentIcon = InstanceType export const USvgIcon = defineComponent({ name: 'USvgIcon', inheritAttrs: false, props: makeIconProps(), setup(props, { attrs }) { const hover = computed(() => { return attrs.isHover }) const active = computed(() => { return attrs.isActive }) const hoverIconClasses = computed( () => `hover:stroke-${getNextColor(attrs.color as ColorName)}` ) const hoverButtonClasses = computed( () => `stroke-${getNextColor(attrs.color as ColorName)}` ) const classes = computed(() => ({ [hoverIconClasses.value]: true, [hoverButtonClasses.value]: hover.value === true && active.value === false, [`stroke-${attrs.color} `]: hover.value === false || active.value === true, })) return () => { return ( ) } }, }) export type USvgIcon = InstanceType export const ULigatureIcon = defineComponent({ name: 'ULigatureIcon', props: makeIconProps(), setup(props) { return () => { return {props.icon} } }, }) export type ULigatureIcon = InstanceType export const UClassIcon = defineComponent({ name: 'UClassIcon', props: makeIconProps(), setup(props) { return () => { return } }, }) export type UClassIcon = InstanceType export const defaultSets: Record = { svg: { component: USvgIcon, }, class: { component: UClassIcon, }, } // Composables export function createIcons(options?: IconOptions) { return mergeDeep( { defaultSet: 'mdi', sets: { ...defaultSets, mdi, }, aliases: { ...aliases, /* eslint-disable max-len */ vuetify: [ 'M8.2241 14.2009L12 21L22 3H14.4459L8.2241 14.2009Z', [ 'M7.26303 12.4733L7.00113 12L2 3H12.5261C12.5261 3 12.5261 3 12.5261 3L7.26303 12.4733Z', 0.6, ], ], 'vuetify-outline': 'svg:M7.26 12.47 12.53 3H2L7.26 12.47ZM14.45 3 8.22 14.2 12 21 22 3H14.45ZM18.6 5 12 16.88 10.51 14.2 15.62 5ZM7.26 8.35 5.4 5H9.13L7.26 8.35Z', /* eslint-enable max-len */ }, }, options ) } export const useIcon = (props: Ref) => { const icons = inject(IconSymbol) if (!icons) throw new Error('Missing Untitled Icons provide!') const iconData = computed(() => { const iconAlias = unref(props) if (!iconAlias) return { component: UComponentIcon } let icon: IconValue | undefined = iconAlias if (typeof icon === 'string') { icon = icon.trim() icon = icon.startsWith('$') ? icons.aliases?.[icon.slice(1)] : icons.aliases?.[icon] } if (!icon) throw new Error(`Could not find aliased icon "${iconAlias}"`) if (Array.isArray(icon)) { return { component: USvgIcon, icon, } } else if (typeof icon !== 'string') { return { component: UComponentIcon, icon, } } const iconSetName = Object.keys(icons.sets).find( (setName) => typeof icon === 'string' && icon.startsWith(`${setName}:`) ) const iconName = iconSetName ? icon.slice(iconSetName.length + 1) : icon const iconSet = icons.sets[iconSetName ?? icons.defaultSet] return { component: iconSet.component, icon: iconName, } }) return { iconData } }