UNPKG

4.12 kBJavaScriptView Raw
1"use strict";
2
3import { defineComponent, toRefs, ref, computed, watch, onMounted, nextTick, h as render } from "vue";
4
5// import PACKAGE_JSON from "../package.json";
6
7// const PACKAGE_NAME = PACKAGE_JSON.name;
8
9// const LIBRARY_NAME = PACKAGE_NAME.split("-").map(character => character.charAt(0).toUpperCase() + character.slice(1).toLowerCase()).join("");
10
11const PACKAGE_NAME = "vue-svg-inline-component";
12
13const LIBRARY_NAME = "VueSvgInlineComponent";
14
15const WINDOW_CACHE_ID = `${LIBRARY_NAME}Cache`;
16
17const WINDOW_VUE_VERSION = window?.Vue?.version;
18
19const EVENTS = [ "update", "error" ];
20
21const DEFAULT_ATTRIBUTES = { class: PACKAGE_NAME };
22
23const REGEXP_SVG_FILENAME = /\.svg(?:[?#].*)?$/i;
24
25const validateSvgFilename = filename => typeof filename === "string" && filename !== "" ? REGEXP_SVG_FILENAME.test(filename) : true;
26
27window[WINDOW_CACHE_ID] = window[WINDOW_CACHE_ID] || new Map;
28
29export default WINDOW_VUE_VERSION && !WINDOW_VUE_VERSION.startsWith("3.") ? console.error(`[${PACKAGE_NAME}] Only Vue@3 is supported! [Vue.version=${WINDOW_VUE_VERSION}]`) : defineComponent({ // eslint-disable-line no-console
30
31 name: PACKAGE_NAME,
32
33 props: {
34 source: {
35 type: String,
36 required: true,
37 default: null,
38 validator: validateSvgFilename
39 },
40 tag: {
41 type: String,
42 required: false,
43 default: "div"
44 },
45 attributes: {
46 type: Object,
47 required: false,
48 default: DEFAULT_ATTRIBUTES
49 },
50 cache: {
51 type: Boolean,
52 required: false,
53 default: true
54 },
55 fetchOptions: {
56 type: Object,
57 required: false,
58 default: null
59 },
60 transformFunction: {
61 type: Function,
62 required: false,
63 default: null
64 },
65 transformFunctionOptions: {
66 // type: any,
67 required: false,
68 default: null
69 },
70 emitUpdates: {
71 type: Boolean,
72 required: false,
73 default: false
74 },
75 emitErrors: {
76 type: Boolean,
77 required: false,
78 default: false
79 },
80 logErrors: {
81 type: Boolean,
82 required: false,
83 default: true
84 }
85 },
86
87 emits: EVENTS,
88
89 setup(props, { emit }) {
90 const {
91 source,
92 cache: isCacheEnabled,
93 fetchOptions,
94 transformFunction,
95 transformFunctionOptions,
96 emitUpdates: canEmitUpdate,
97 emitErrors: canEmitError,
98 logErrors: canLogError
99 } = toRefs(props);
100
101 const canUseCache = computed(() => isCacheEnabled.value && !fetchOptions.value);
102
103 const svg = ref();
104
105 const emitError = error => {
106 if(canEmitError.value) emit(EVENTS[1], error);
107 if(canLogError.value) console.error(`[${PACKAGE_NAME}] ${error}`); // eslint-disable-line no-console
108 };
109
110 const emitUpdate = () => {
111 if(canEmitUpdate.value) nextTick()
112 .then(() => emit(EVENTS[0], svg.value))
113 .catch(emitError);
114 };
115
116 const fetchSvg = () => {
117 if(!source.value) return svg.value = null;
118 (canUseCache.value && window[WINDOW_CACHE_ID].has(source.value) ? Promise.resolve(window[WINDOW_CACHE_ID].get(source.value)) : window.fetch(source.value, fetchOptions.value)
119 .then(response => {
120 if(response.status < 200 || response.status >= 400) throw new Error(`Wrong HTTP response status code! [response.status=${response.status}]`);
121 return response.text();
122 }))
123 .then(response => {
124 if(canUseCache.value && !window[WINDOW_CACHE_ID].has(source.value)) window[WINDOW_CACHE_ID].set(source.value, response);
125 svg.value = transformFunction.value ? transformFunction.value.call(null, response, transformFunctionOptions.value, props) : response;
126 })
127 .catch(emitError);
128 };
129
130 onMounted(() => {
131 fetchSvg();
132 watch([ source, fetchOptions, transformFunction, transformFunctionOptions ], fetchSvg);
133 watch(svg, emitUpdate);
134 });
135
136 return { svg };
137 },
138
139 render() {
140 const { tag, attributes, svg } = this;
141
142 if(!svg) return;
143
144 if(!tag) {
145 const { tagName: tag, attributes, innerHTML } = (new DOMParser()).parseFromString(svg, "text/xml").getElementsByTagName("svg")[0];
146 return render(tag, Object.assign({}, Array.from(attributes).reduce((accumulator, { name, value }) => Object.assign(accumulator, { [name]: value }), {}), { innerHTML }));
147 }
148
149 return render(tag, Object.assign({}, attributes, { innerHTML: svg }));
150 }
151
152});