152 lines
3.9 KiB
Vue
152 lines
3.9 KiB
Vue
<template>
|
|
<svg ref="svg" v-bind="svgAttributes" v-html="svgContent" :class="calculatedClasses"></svg>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import { computed, nextTick, useTemplateRef, watch } from "vue";
|
|
|
|
import Caret from "../iconic/svg/smart/caret";
|
|
import Check from "../iconic/svg/smart/check";
|
|
import CircleCheck from "../iconic/svg/smart/circle-check";
|
|
import Link from "../iconic/svg/smart/link";
|
|
import Lock from "../iconic/svg/smart/lock";
|
|
import Menu from "../iconic/svg/smart/menu";
|
|
import QuestionMark from "../iconic/svg/smart/question-mark.svg"
|
|
import Person from "../iconic/svg/smart/person";
|
|
import Pencil from "../iconic/svg/smart/pencil";
|
|
import Star from "../iconic/svg/smart/star";
|
|
import StarEmpty from "../iconic/svg/smart/star-empty";
|
|
import Warning from "../iconic/svg/smart/warning";
|
|
import X from "../iconic/svg/smart/x";
|
|
|
|
const APIS = {};
|
|
const LOADED_APIS = {};
|
|
|
|
window._Iconic = {
|
|
smartIconApis: APIS
|
|
};
|
|
|
|
let globalIdCounter = 0;
|
|
|
|
const iconMap = {
|
|
caret: Caret,
|
|
check: Check,
|
|
'circle-check': CircleCheck,
|
|
link: Link,
|
|
lock: Lock,
|
|
menu: Menu,
|
|
pencil: Pencil,
|
|
person: Person,
|
|
'question-mark': QuestionMark,
|
|
star: Star,
|
|
'star-empty': StarEmpty,
|
|
warning: Warning,
|
|
x: X
|
|
};
|
|
|
|
export default {
|
|
props: {
|
|
icon: {
|
|
type: String,
|
|
required: true,
|
|
validator: (i) => iconMap[i] !== undefined
|
|
},
|
|
|
|
size: {
|
|
type: String,
|
|
default: "lg",
|
|
validator: (s) => ["sm", "md", "lg"].indexOf(s) >= 0
|
|
},
|
|
|
|
iconSizeOverride: {
|
|
type: String,
|
|
validator: (s) => ["sm", "md", "lg", null].indexOf(s) >= 0
|
|
},
|
|
|
|
displaySizeOverride: {
|
|
type: String,
|
|
validator: (s) => ["sm", "md", "lg", null].indexOf(s) >= 0
|
|
}
|
|
},
|
|
|
|
setup(props) {
|
|
const svgElement = useTemplateRef("svg");
|
|
const svgData = computed(() => iconMap[props.icon]);
|
|
const svgAttributes = computed(() => svgData.value.attributes);
|
|
const svgName = computed(() => svgAttributes.value['data-icon']);
|
|
const svgContent = computed(() => {
|
|
let content = String(svgData.value.content);
|
|
|
|
for (let idRep of svgData.value.idReplacements) {
|
|
let newId = `__new_id_${globalIdCounter}`;
|
|
globalIdCounter += 1;
|
|
|
|
content = content.replace(new RegExp(idRep, "g"), newId);
|
|
}
|
|
|
|
return content;
|
|
});
|
|
|
|
const calculatedClasses = computed(() => {
|
|
const classes = (svgAttributes.value.class || "").split(" ");
|
|
|
|
classes.push(`iconic-${props.size}`);
|
|
|
|
if (props.iconSizeOverride) {
|
|
classes.push(`iconic-icon-${props.iconSizeOverride}`);
|
|
}
|
|
|
|
if (props.displaySizeOverride) {
|
|
classes.push(`iconic-size-${props.displaySizeOverride}`);
|
|
}
|
|
|
|
return classes;
|
|
});
|
|
|
|
function ensureSvgApi(name, scripts) {
|
|
if (!name) { return; }
|
|
if (LOADED_APIS[name] !== true) {
|
|
for (let sb of scripts) {
|
|
try {
|
|
new Function(sb)(window);
|
|
} catch (e) {
|
|
console.log(sb);
|
|
console.log(e);
|
|
}
|
|
}
|
|
LOADED_APIS[name] = true;
|
|
}
|
|
}
|
|
|
|
function setupSvgApi(name) {
|
|
const apis = APIS;
|
|
if (apis && apis[name]) {
|
|
const iconApi = apis[name](svgElement.value);
|
|
for (let func in iconApi) svgElement.value[func] = iconApi[func]
|
|
} else {
|
|
svgElement.value.update = function() {}
|
|
}
|
|
svgElement.value.update();
|
|
}
|
|
|
|
watch(
|
|
() => props.icon,
|
|
() => {
|
|
ensureSvgApi(svgName.value, svgData.value.scriptBlocks);
|
|
nextTick(() => setupSvgApi(svgName.value));
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
return {
|
|
svgData,
|
|
svgAttributes,
|
|
svgName,
|
|
svgContent,
|
|
calculatedClasses
|
|
};
|
|
}
|
|
}
|
|
|
|
</script> |