export-svg-typescript 0.1.0

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/demo/index.ts ADDED
@@ -0,0 +1,104 @@
1
+ // Do a Barrel Roll index of SVG icons as JS exports, enabling tree shaking to only the icons you import.
2
+
3
+
4
+ /**
5
+ * Returns a customized SVG string for loading icon bouncy-ball
6
+ *
7
+ * ![loading-bouncy-ball](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHN0eWxlPSJzaGFwZS1yZW5kZXJpbmc6IGF1dG87IGRpc3BsYXk6IGJsb2NrOyAiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48Zz48Y2lyY2xlIGZpbGw9IiNlMTViNjQiIHI9IjEzIiBjeT0iMjMiIGN4PSI1MCI+CiAgPGFuaW1hdGUgdmFsdWVzPSIyMzs3NzsyMyIga2V5VGltZXM9IjA7MC41OzEiIGtleVNwbGluZXM9IjAuNDUgMCAwLjkgMC41NTswIDAuNDUgMC41NSAwLjkiIGNhbGNNb2RlPSJzcGxpbmUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBkdXI9IjFzIiBhdHRyaWJ1dGVOYW1lPSJjeSI+PC9hbmltYXRlPgo8L2NpcmNsZT48Zz48L2c+PC9nPjwvc3ZnPg==)
8
+ * @param {Object} options - Configuration options
9
+ * @param {string[]} [options.colors] - Array of hex colors to replace existing colors
10
+ * @param {number} [options.width] - Width of the SVG (default: 200)
11
+ * @param {number} [options.height] - Height of the SVG (default: 200)
12
+ * @param {number} [options.size] - Size for both width and height
13
+ * @example loadingBouncyBall({ colors: ['#0099e5', '#ff4c4c'], size: 100 });
14
+ * @returns {string} SVG string with applied customizations
15
+ */
16
+ export const loadingBouncyBall = (options: LoadingOptions = {}) => customSVG(options,
17
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; "><g><circle fill="#e15b64" r="13" cy="23" cx="50"><animate values="23;77;23" keyTimes="0;0.5;1" keySplines="0.45 0 0.9 0.55;0 0.45 0.55 0.9" calcMode="spline" repeatCount="indefinite" dur="1s" attributeName="cy"></animate></circle><g></g></g></svg>`);
18
+
19
+
20
+ /**
21
+ * Returns a customized SVG string for loading icon double-ring
22
+ *
23
+ * ![loading-double-ring](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHN0eWxlPSJzaGFwZS1yZW5kZXJpbmc6IGF1dG87IGRpc3BsYXk6IGJsb2NrOyAiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48Zz48Y2lyY2xlIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgZmlsbD0ibm9uZSIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIHN0cm9rZT0iIzAwOTllNSIgc3Ryb2tlLXdpZHRoPSI4IiByPSIzMiIgY3k9IjUwIiBjeD0iNTAiPgogIDxhbmltYXRlVHJhbnNmb3JtIHZhbHVlcz0iMCA1MCA1MDszNjAgNTAgNTAiIGtleVRpbWVzPSIwOzEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBkdXI9IjFzIiB0eXBlPSJyb3RhdGUiIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSI+PC9hbmltYXRlVHJhbnNmb3JtPgo8L2NpcmNsZT4KPGNpcmNsZSBzdHJva2UtbGluZWNhcD0icm91bmQiIGZpbGw9Im5vbmUiIHN0cm9rZS1kYXNob2Zmc2V0PSIzNi4xMjgzMTU1MTYyODI2MiIgc3Ryb2tlLWRhc2hhcnJheT0iMzYuMTI4MzE1NTE2MjgyNjIgMzYuMTI4MzE1NTE2MjgyNjIiIHN0cm9rZT0iI2ZmNGM0YyIgc3Ryb2tlLXdpZHRoPSI4IiByPSIyMyIgY3k9IjUwIiBjeD0iNTAiPgogIDxhbmltYXRlVHJhbnNmb3JtIHZhbHVlcz0iMCA1MCA1MDstMzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIgdHlwZT0icm90YXRlIiBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iPjwvYW5pbWF0ZVRyYW5zZm9ybT4KPC9jaXJjbGU+PGc+PC9nPjwvZz48L3N2Zz4=)
24
+ * @param {Object} options - Configuration options
25
+ * @param {string[]} [options.colors] - Array of hex colors to replace existing colors
26
+ * @param {number} [options.width] - Width of the SVG (default: 200)
27
+ * @param {number} [options.height] - Height of the SVG (default: 200)
28
+ * @param {number} [options.size] - Size for both width and height
29
+ * @example loadingDoubleRing({ colors: ['#0099e5', '#ff4c4c'], size: 100 });
30
+ * @returns {string} SVG string with applied customizations
31
+ */
32
+ export const loadingDoubleRing = (options: LoadingOptions = {}) => customSVG(options,
33
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; "><g><circle stroke-linecap="round" fill="none" stroke-dasharray="50.26548245743669 50.26548245743669" stroke="#0099e5" stroke-width="8" r="32" cy="50" cx="50"><animateTransform values="0 50 50;360 50 50" keyTimes="0;1" repeatCount="indefinite" dur="1s" type="rotate" attributeName="transform"></animateTransform></circle><circle stroke-linecap="round" fill="none" stroke-dashoffset="36.12831551628262" stroke-dasharray="36.12831551628262 36.12831551628262" stroke="#ff4c4c" stroke-width="8" r="23" cy="50" cx="50"><animateTransform values="0 50 50;-360 50 50" keyTimes="0;1" repeatCount="indefinite" dur="1s" type="rotate" attributeName="transform"></animateTransform></circle><g></g></g></svg>`);
34
+
35
+
36
+ /**
37
+ * Returns a customized SVG string for loading icon eclipse
38
+ *
39
+ * ![loading-eclipse](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHN0eWxlPSJzaGFwZS1yZW5kZXJpbmc6IGF1dG87IGRpc3BsYXk6IGJsb2NrOyI+PGc+PHBhdGggc3Ryb2tlPSJub25lIiBmaWxsPSIjZmZiOTAwIiBkPSJNMTAgNTBBNDAgNDAgMCAwIDAgOTAgNTBBNDAgNDIgMCAwIDEgMTAgNTAiPgogIDxhbmltYXRlVHJhbnNmb3JtIHZhbHVlcz0iMCA1MCA1MTszNjAgNTAgNTEiIGtleVRpbWVzPSIwOzEiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiBkdXI9IjFzIiB0eXBlPSJyb3RhdGUiIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSI+PC9hbmltYXRlVHJhbnNmb3JtPgo8L3BhdGg+PGc+PC9nPjwvZz48L3N2Zz4=)
40
+ * @param {Object} options - Configuration options
41
+ * @param {string[]} [options.colors] - Array of hex colors to replace existing colors
42
+ * @param {number} [options.width] - Width of the SVG (default: 200)
43
+ * @param {number} [options.height] - Height of the SVG (default: 200)
44
+ * @param {number} [options.size] - Size for both width and height
45
+ * @example loadingEclipse({ colors: ['#0099e5', '#ff4c4c'], size: 100 });
46
+ * @returns {string} SVG string with applied customizations
47
+ */
48
+ export const loadingEclipse = (options: LoadingOptions = {}) => customSVG(options,
49
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block;"><g><path stroke="none" fill="#ffb900" d="M10 50A40 40 0 0 0 90 50A40 42 0 0 1 10 50"><animateTransform values="0 50 51;360 50 51" keyTimes="0;1" repeatCount="indefinite" dur="1s" type="rotate" attributeName="transform"></animateTransform></path><g></g></g></svg>`);
50
+
51
+ /**
52
+ * Shared utility function for processing SVG icons
53
+ * @param {Object} options - Configuration options
54
+ * @param {boolean} [options.raw] - Whether to return the raw SVG string or an img tag
55
+ * @param {string[]} [options.colors] - Array of hex colors to replace existing colors
56
+ * @param {number|string} [options.width] - Width of the SVG
57
+ * @param {number|string} [options.height] - Height of the SVG
58
+ * @param {number|string} [options.size] - Size for both width and height (overrides width/height)
59
+ * @param {string} svgString - The original SVG content
60
+ * @returns {string} SVG string with applied customizations
61
+ */
62
+ function customSVG( options: LoadingOptions, svgString: string) {
63
+ const { colors = [], width, height, size, raw = false } = options;
64
+
65
+ const widthMatch = svgString.match(/width="(d+)"/);
66
+ const heightMatch = svgString.match(/height="(d+)"/);
67
+ const finalWidth = size || width || widthMatch?.[1] || '100';
68
+ const finalHeight = size || height || heightMatch?.[1] || '100';
69
+
70
+ svgString = svgString.replace(/width="[^"]*"/g, `width="${finalWidth}"`);
71
+ svgString = svgString.replace(/height="[^"]*"/g, `height="${finalHeight}"`);
72
+
73
+ // If colors array is provided, replace hex colors in order of appearance
74
+ if (colors && colors.length > 0) {
75
+ const hexColorRegex = /#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}/g;
76
+ let colorIndex = 0;
77
+
78
+ svgString = svgString.replace(hexColorRegex, (match) => {
79
+ if (colorIndex < colors.length) {
80
+ const replacement = colors[colorIndex];
81
+ colorIndex++;
82
+ return replacement?.startsWith('#') ? replacement : `#${replacement}`;
83
+ }
84
+ return match; // Keep original color if no replacement available
85
+ });
86
+ }
87
+ if (!raw)
88
+ svgString = `<img alt="loading-icon" src="data:image/svg+xml;utf8,${encodeURIComponent(svgString)}" />`
89
+
90
+ return svgString;
91
+ }
92
+ interface LoadingOptions {
93
+ /** Array of hex colors to replace existing colors, in order of appearance in SVG*/
94
+ colors?: string[];
95
+ /** Width of the SVG */
96
+ width?: number;
97
+ /** Height of the SVG */
98
+ height?: number;
99
+ /** Size for both width and height (overrides width/height) */
100
+ size?: number;
101
+ /** Whether to return the raw SVG string or an img tag */
102
+ raw?: boolean;
103
+ }
104
+
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><circle fill="#e15b64" r="13" cy="23" cx="50">
2
+ <animate values="23;77;23" keyTimes="0;0.5;1" keySplines="0.45 0 0.9 0.55;0 0.45 0.55 0.9" calcMode="spline" repeatCount="indefinite" dur="1s" attributeName="cy"></animate>
3
+ </circle><g></g></g></svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><circle stroke-linecap="round" fill="none" stroke-dasharray="50.26548245743669 50.26548245743669" stroke="#0099e5" stroke-width="8" r="32" cy="50" cx="50">
2
+ <animateTransform values="0 50 50;360 50 50" keyTimes="0;1" repeatCount="indefinite" dur="1s" type="rotate" attributeName="transform"></animateTransform>
3
+ </circle>
4
+ <circle stroke-linecap="round" fill="none" stroke-dashoffset="36.12831551628262" stroke-dasharray="36.12831551628262 36.12831551628262" stroke="#ff4c4c" stroke-width="8" r="23" cy="50" cx="50">
5
+ <animateTransform values="0 50 50;-360 50 50" keyTimes="0;1" repeatCount="indefinite" dur="1s" type="rotate" attributeName="transform"></animateTransform>
6
+ </circle><g></g></g></svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block;"><g><path stroke="none" fill="#ffb900" d="M10 50A40 40 0 0 0 90 50A40 42 0 0 1 10 50">
2
+ <animateTransform values="0 50 51;360 50 51" keyTimes="0;1" repeatCount="indefinite" dur="1s" type="rotate" attributeName="transform"></animateTransform>
3
+ </path><g></g></g></svg>
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "fs";
4
+ import path from "path";
5
+
6
+ /**
7
+ * Script to process SVG files from input folder and generates JS export index,
8
+ * Barrel Roll for the icons js files, enabling tree shaking to only the icons the
9
+ * user imports, enables customizing colors and size, and shows tooltip preview.
10
+ * usage: node convert-svg-to-js.js -i ./src/icons-svg -o ./dist/icons
11
+ * @param {string} inputFolder - Path to folder containing SVG files
12
+ * @param {string} outputFolder - Path to folder where JS files will be generated
13
+ */
14
+ export function convertSVGFolderToExportIndex(inputFolder, indexPath) {
15
+ // Read all files from input folder
16
+ const files = fs.readdirSync(inputFolder);
17
+ const svgFiles = files.filter(
18
+ (file) => path.extname(file).toLowerCase() === ".svg"
19
+ );
20
+
21
+ // Generate index file
22
+
23
+ let indexContent = `// Do a Barrel Roll index of SVG icons as JS exports, enabling tree shaking to only the icons you import.\n\n`;
24
+ const exportData = [];
25
+
26
+ svgFiles.forEach((svgFile) => {
27
+ const inputPath = path.join(inputFolder, svgFile);
28
+ const baseName = path.basename(svgFile, ".svg");
29
+
30
+ // Read SVG content
31
+ const svgContent = fs.readFileSync(inputPath, "utf8");
32
+
33
+ // Extract original dimensions from SVG
34
+ const widthMatch = svgContent.match(/width="(\d+)"/);
35
+ const heightMatch = svgContent.match(/height="(\d+)"/);
36
+ const defaultWidth = widthMatch ? widthMatch[1] : "100";
37
+ const defaultHeight = heightMatch ? heightMatch[1] : "100";
38
+
39
+ // Convert SVG string to Base64
40
+ const svgBase64 = `data:image/svg+xml;base64,${btoa(
41
+ unescape(encodeURIComponent(svgContent))
42
+ )}`;
43
+
44
+ const jsContent = `
45
+ /**
46
+ * Returns a customized SVG string for loading icon ${baseName.replace(/loading-/g, "" )}
47
+ *
48
+ * ![${baseName}](${svgBase64})
49
+ * @param {Object} options - Configuration options
50
+ * @param {string[]} [options.colors] - Array of hex colors to replace existing colors
51
+ * @param {number} [options.width] - Width of the SVG (default: ${defaultWidth})
52
+ * @param {number} [options.height] - Height of the SVG (default: ${defaultHeight})
53
+ * @param {number} [options.size] - Size for both width and height
54
+ * @example ${toCamelCase(
55
+ baseName
56
+ )}({ colors: ['#0099e5', '#ff4c4c'], size: 100 });
57
+ * @returns {string} SVG string with applied customizations
58
+ */
59
+ export const ${toCamelCase(baseName)} = (options: LoadingOptions = {}) => customSVG(options,
60
+ \`${svgContent
61
+ .replace(/`/g, "\\`")
62
+ .replace(' xmlns:xlink="http://www.w3.org/1999/xlink"', "")
63
+ .replace(/\n/g, "")
64
+ .replace(/\$/g, "\\$")
65
+ .replace(/ +/g, " ")
66
+ .replace(/> </g, "><")}\`);\n\n`;
67
+
68
+ // Generate imports
69
+ indexContent += jsContent;
70
+
71
+ // Store export data for index file
72
+ exportData.push({
73
+ fileName: svgFile,
74
+ baseName: baseName,
75
+ functionName: toCamelCase(baseName),
76
+ content: jsContent,
77
+ svgBase64: svgBase64,
78
+ defaultWidth: defaultWidth,
79
+ defaultHeight: defaultHeight,
80
+ });
81
+ });
82
+
83
+ indexContent += `/**
84
+ * Shared utility function for processing SVG icons
85
+ * @param {Object} options - Configuration options
86
+ * @param {boolean} [options.raw] - Whether to return the raw SVG string or an img tag
87
+ * @param {string[]} [options.colors] - Array of hex colors to replace existing colors
88
+ * @param {number|string} [options.width] - Width of the SVG
89
+ * @param {number|string} [options.height] - Height of the SVG
90
+ * @param {number|string} [options.size] - Size for both width and height (overrides width/height)
91
+ * @param {string} svgString - The original SVG content
92
+ * @returns {string} SVG string with applied customizations
93
+ */
94
+ function customSVG( options: LoadingOptions, svgString: string) {
95
+ const { colors = [], width, height, size, raw = false } = options;
96
+
97
+ const widthMatch = svgString.match(/width="(d+)"/);
98
+ const heightMatch = svgString.match(/height="(d+)"/);
99
+ const finalWidth = size || width || widthMatch?.[1] || '100';
100
+ const finalHeight = size || height || heightMatch?.[1] || '100';
101
+
102
+ svgString = svgString.replace(/width="[^"]*"/g, \`width="\${finalWidth}"\`);
103
+ svgString = svgString.replace(/height="[^"]*"/g, \`height="\${finalHeight}"\`);
104
+
105
+ // If colors array is provided, replace hex colors in order of appearance
106
+ if (colors && colors.length > 0) {
107
+ const hexColorRegex = /#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}/g;
108
+ let colorIndex = 0;
109
+
110
+ svgString = svgString.replace(hexColorRegex, (match) => {
111
+ if (colorIndex < colors.length) {
112
+ const replacement = colors[colorIndex];
113
+ colorIndex++;
114
+ return replacement?.startsWith('#') ? replacement : \`#\${replacement}\`;
115
+ }
116
+ return match; // Keep original color if no replacement available
117
+ });
118
+ }
119
+ if (!raw)
120
+ svgString = \`<img alt="loading-icon" src="data:image/svg+xml;utf8,\${encodeURIComponent(svgString)}" />\`
121
+
122
+ return svgString;
123
+ }
124
+ interface LoadingOptions {
125
+ /** Array of hex colors to replace existing colors, in order of appearance in SVG*/
126
+ colors?: string[];
127
+ /** Width of the SVG */
128
+ width?: number;
129
+ /** Height of the SVG */
130
+ height?: number;
131
+ /** Size for both width and height (overrides width/height) */
132
+ size?: number;
133
+ /** Whether to return the raw SVG string or an img tag */
134
+ raw?: boolean;
135
+ }
136
+
137
+ `;
138
+
139
+ fs.writeFileSync(indexPath, indexContent);
140
+
141
+
142
+
143
+
144
+ console.log(
145
+ `✨ Converted ${svgFiles.length} SVG files to customizable JS export files`
146
+ );
147
+ }
148
+
149
+ /**
150
+ * Convert string to camelCase
151
+ * @param {string} str
152
+ * @returns {string}
153
+ */
154
+ function toCamelCase(str) {
155
+ return str
156
+ .replace(/[^a-zA-Z0-9]/g, " ")
157
+ .replace(/\s+/g, " ")
158
+ .split(" ")
159
+ .map((word, index) => {
160
+ if (index === 0) {
161
+ return word.toLowerCase();
162
+ }
163
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
164
+ })
165
+ .join("");
166
+ }
167
+
168
+ // Get input/output folders from command line args
169
+ const args = process.argv.slice(2);
170
+ const inputIndex = args.indexOf("-i");
171
+ const outputIndex = args.indexOf("-o");
172
+
173
+ const inputFolder = inputIndex >= 0 ? args[inputIndex + 1] : "./svg"; // Folder containing SVG files
174
+ const outputPath = outputIndex >= 0 ? args[outputIndex + 1] : "./index.ts"; // Folder for generated JS files
175
+
176
+ // Run the converter
177
+ convertSVGFolderToExportIndex(inputFolder, outputPath);
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "export-svg-typescript",
3
+ "module": "convert-svg-to-export.js",
4
+ "author": "vtempest",
5
+ "license": "MIT",
6
+ "version": "0.1.0",
7
+ "description": "Export SVG to TypeScript",
8
+ "type": "module",
9
+ "scripts": {
10
+ "demo": "node export-svg-typescript.js -i ./demo -o ./demo/index.ts"
11
+ },
12
+ "bin": {
13
+ "export-svg-typescript": "convert-svg-to-export.js"
14
+ }
15
+ }
package/readme.md ADDED
@@ -0,0 +1,28 @@
1
+ ## export-svg-typescript
2
+
3
+ Convert a folder of SVG icons into a color-customizable, tree-shakable TypeScript export `index.ts` that works with any component framework without SVG or Vite compiler issues.
4
+
5
+ 1. Barrel Roll: Exports all icons as named functions for tree shaking to only the ones actually used.
6
+ 2. Typescript Tooltip Previews: Each export includes a tooltip preview (Base64-encoded).
7
+ 3. Customizable: Change icon colors, size, and dimensions at runtime. Can return SVG or IMG tag with SVG as source.
8
+ 4. CLI Tool: Use directly from the command line or in npm scripts: `npx
9
+
10
+ ### Install
11
+ ```
12
+ npm install -g export-svg-typescript
13
+ ```
14
+ ```
15
+ # or use npx without installing globally
16
+ npx export-svg-typescript -i ./src/icons -o ./src/icons/index.ts
17
+ ```
18
+
19
+ ### Example
20
+
21
+ Clone this repo and run `npm run demo` to see icons in demo folder.
22
+
23
+ ```javascript
24
+ import { loadingDoubleRing } from './demo';
25
+
26
+ loadingDoubleRing({size: 200, colors: ["#5345bb"] })
27
+ ```
28
+ ![screenshot](https://i.imgur.com/aXczCC2.png)