@iconify/tools 4.0.1 → 4.0.2
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/lib/optimise/figma.cjs +76 -41
- package/lib/optimise/figma.d.cts +2 -1
- package/lib/optimise/figma.d.mts +2 -1
- package/lib/optimise/figma.d.ts +2 -1
- package/lib/optimise/figma.mjs +77 -42
- package/package.json +1 -1
package/lib/optimise/figma.cjs
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const utils = require('@iconify/utils');
|
|
4
|
+
const svg_cleanup_inlineStyle = require('../svg/cleanup/inline-style.cjs');
|
|
3
5
|
const svg_data_tags = require('../svg/data/tags.cjs');
|
|
6
|
+
const svg_parse = require('../svg/parse.cjs');
|
|
4
7
|
const optimise_unwrap = require('./unwrap.cjs');
|
|
8
|
+
require('../css/parse.cjs');
|
|
9
|
+
require('../css/parser/tokens.cjs');
|
|
10
|
+
require('../css/parser/error.cjs');
|
|
11
|
+
require('../css/parser/strings.cjs');
|
|
12
|
+
require('../css/parser/text.cjs');
|
|
13
|
+
require('../svg/data/attributes.cjs');
|
|
5
14
|
|
|
6
15
|
function isTinyNumber(value, limit) {
|
|
7
16
|
const num = parseInt(value);
|
|
@@ -25,8 +34,10 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
25
34
|
...childNode.attribs
|
|
26
35
|
};
|
|
27
36
|
delete attribs["fill"];
|
|
28
|
-
const fill = childNode.attribs["fill"]
|
|
29
|
-
|
|
37
|
+
const fill = childNode.attribs["fill"];
|
|
38
|
+
const colorValue = fill ? utils.stringToColor(fill) : null;
|
|
39
|
+
const colorString = colorValue ? utils.colorToString(colorValue) : null;
|
|
40
|
+
if (fill && colorString !== "#fff") {
|
|
30
41
|
console.warn(
|
|
31
42
|
"Unxepected fill on clip path:",
|
|
32
43
|
childNode.attribs["fill"]
|
|
@@ -43,24 +54,6 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
43
54
|
}
|
|
44
55
|
delete attribs["width"];
|
|
45
56
|
delete attribs["height"];
|
|
46
|
-
for (const attr in childNode.attribs) {
|
|
47
|
-
const value = childNode.attribs[attr];
|
|
48
|
-
switch (attr) {
|
|
49
|
-
case "rx":
|
|
50
|
-
case "ry":
|
|
51
|
-
case "x":
|
|
52
|
-
case "y":
|
|
53
|
-
if (value === "0") {
|
|
54
|
-
delete attribs[attr];
|
|
55
|
-
}
|
|
56
|
-
break;
|
|
57
|
-
case "transform":
|
|
58
|
-
if (value === "") {
|
|
59
|
-
delete attribs[attr];
|
|
60
|
-
}
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
57
|
break;
|
|
65
58
|
}
|
|
66
59
|
default:
|
|
@@ -97,6 +90,58 @@ function remove(svg) {
|
|
|
97
90
|
optimise_unwrap.unwrapEmptyGroup(svg);
|
|
98
91
|
let content = svg.toString();
|
|
99
92
|
const backup = content;
|
|
93
|
+
const isPenpot = content.includes("frame-clip-def");
|
|
94
|
+
if (isPenpot) {
|
|
95
|
+
svg_cleanup_inlineStyle.cleanupInlineStyle(svg);
|
|
96
|
+
svg_parse.parseSVG(svg, (item) => {
|
|
97
|
+
const tagName = item.tagName;
|
|
98
|
+
for (const attr in item.element.attribs) {
|
|
99
|
+
const value = item.element.attribs[attr];
|
|
100
|
+
switch (attr) {
|
|
101
|
+
case "id":
|
|
102
|
+
if (!svg_data_tags.maskTags.has(tagName) && !svg_data_tags.symbolTag.has(tagName)) {
|
|
103
|
+
item.$element.removeAttr(attr);
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
case "class":
|
|
107
|
+
case "xmlns:xlink":
|
|
108
|
+
case "version":
|
|
109
|
+
item.$element.removeAttr(attr);
|
|
110
|
+
break;
|
|
111
|
+
case "transform": {
|
|
112
|
+
const trimmed = value.replace(/\s+/g, "").replace(/\.0+/g, "");
|
|
113
|
+
if (!trimmed || trimmed === "matrix(1,0,0,1,0,0)") {
|
|
114
|
+
item.$element.removeAttr(attr);
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
case "rx":
|
|
119
|
+
case "ry":
|
|
120
|
+
case "x":
|
|
121
|
+
case "y":
|
|
122
|
+
if (value === "0") {
|
|
123
|
+
item.$element.removeAttr(attr);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
case "fill-opacity":
|
|
127
|
+
case "stroke-opacity":
|
|
128
|
+
case "opacity":
|
|
129
|
+
if (value === "1") {
|
|
130
|
+
item.$element.removeAttr(attr);
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
case "fill":
|
|
134
|
+
case "stroke": {
|
|
135
|
+
const colorValue = utils.stringToColor(value);
|
|
136
|
+
if (colorValue?.type === "rgb") {
|
|
137
|
+
item.$element.attr(attr, utils.colorToString(colorValue));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
content = svg.toString();
|
|
144
|
+
}
|
|
100
145
|
const clipPathBlocks = content.match(
|
|
101
146
|
/<clipPath[^>]*>[\s\S]+?<\/clipPath>/g
|
|
102
147
|
);
|
|
@@ -105,7 +150,6 @@ function remove(svg) {
|
|
|
105
150
|
const lines = content.split(split);
|
|
106
151
|
content = lines.shift() + split + lines.join("");
|
|
107
152
|
}
|
|
108
|
-
content = content.replaceAll('class="frame-clip-def frame-clip"', "");
|
|
109
153
|
if (content.includes("<defs>")) {
|
|
110
154
|
content = content.replace(/<\/?defs>/g, "");
|
|
111
155
|
}
|
|
@@ -138,30 +182,21 @@ function remove(svg) {
|
|
|
138
182
|
if (typeof clipID !== "string") {
|
|
139
183
|
return false;
|
|
140
184
|
}
|
|
141
|
-
const checkClipPath = (node) => {
|
|
142
|
-
const id = node.attribs["id"];
|
|
143
|
-
if (id !== clipID) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const result = checkClipPathNode(
|
|
147
|
-
node,
|
|
148
|
-
svg.viewBox.width,
|
|
149
|
-
svg.viewBox.height
|
|
150
|
-
);
|
|
151
|
-
cheerio(node).remove();
|
|
152
|
-
return result;
|
|
153
|
-
};
|
|
154
185
|
const findClipPath = () => {
|
|
155
186
|
for (let i = 0; i < children.length; i++) {
|
|
156
187
|
const node = children[i];
|
|
157
|
-
if (node.type === "tag") {
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
160
|
-
const result =
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
188
|
+
if (node.type === "tag" && node.tagName === "clipPath") {
|
|
189
|
+
const id = node.attribs["id"];
|
|
190
|
+
if (id === clipID) {
|
|
191
|
+
const result = checkClipPathNode(
|
|
192
|
+
node,
|
|
193
|
+
svg.viewBox.width,
|
|
194
|
+
svg.viewBox.height
|
|
195
|
+
);
|
|
196
|
+
cheerio(node).remove();
|
|
197
|
+
return result;
|
|
164
198
|
}
|
|
199
|
+
return;
|
|
165
200
|
}
|
|
166
201
|
}
|
|
167
202
|
};
|
package/lib/optimise/figma.d.cts
CHANGED
|
@@ -4,7 +4,8 @@ import '@iconify/types';
|
|
|
4
4
|
import '@iconify/utils/lib/customisations/defaults';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements
|
|
7
|
+
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements.
|
|
8
|
+
* Also removes mess generated by Penpot
|
|
8
9
|
*
|
|
9
10
|
* Function was originally designed for Figma only, but later added support for Penpot
|
|
10
11
|
*/
|
package/lib/optimise/figma.d.mts
CHANGED
|
@@ -4,7 +4,8 @@ import '@iconify/types';
|
|
|
4
4
|
import '@iconify/utils/lib/customisations/defaults';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements
|
|
7
|
+
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements.
|
|
8
|
+
* Also removes mess generated by Penpot
|
|
8
9
|
*
|
|
9
10
|
* Function was originally designed for Figma only, but later added support for Penpot
|
|
10
11
|
*/
|
package/lib/optimise/figma.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ import '@iconify/types';
|
|
|
4
4
|
import '@iconify/utils/lib/customisations/defaults';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements
|
|
7
|
+
* Removes clip path from SVG, which Figma and Penpot add to icons that might have overflowing elements.
|
|
8
|
+
* Also removes mess generated by Penpot
|
|
8
9
|
*
|
|
9
10
|
* Function was originally designed for Figma only, but later added support for Penpot
|
|
10
11
|
*/
|
package/lib/optimise/figma.mjs
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { stringToColor, colorToString } from '@iconify/utils';
|
|
2
|
+
import { cleanupInlineStyle } from '../svg/cleanup/inline-style.mjs';
|
|
3
|
+
import { maskTags, symbolTag, defsTag } from '../svg/data/tags.mjs';
|
|
4
|
+
import { parseSVG } from '../svg/parse.mjs';
|
|
2
5
|
import { unwrapEmptyGroup } from './unwrap.mjs';
|
|
6
|
+
import '../css/parse.mjs';
|
|
7
|
+
import '../css/parser/tokens.mjs';
|
|
8
|
+
import '../css/parser/error.mjs';
|
|
9
|
+
import '../css/parser/strings.mjs';
|
|
10
|
+
import '../css/parser/text.mjs';
|
|
11
|
+
import '../svg/data/attributes.mjs';
|
|
3
12
|
|
|
4
13
|
function isTinyNumber(value, limit) {
|
|
5
14
|
const num = parseInt(value);
|
|
@@ -23,8 +32,10 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
23
32
|
...childNode.attribs
|
|
24
33
|
};
|
|
25
34
|
delete attribs["fill"];
|
|
26
|
-
const fill = childNode.attribs["fill"]
|
|
27
|
-
|
|
35
|
+
const fill = childNode.attribs["fill"];
|
|
36
|
+
const colorValue = fill ? stringToColor(fill) : null;
|
|
37
|
+
const colorString = colorValue ? colorToString(colorValue) : null;
|
|
38
|
+
if (fill && colorString !== "#fff") {
|
|
28
39
|
console.warn(
|
|
29
40
|
"Unxepected fill on clip path:",
|
|
30
41
|
childNode.attribs["fill"]
|
|
@@ -41,24 +52,6 @@ function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
|
41
52
|
}
|
|
42
53
|
delete attribs["width"];
|
|
43
54
|
delete attribs["height"];
|
|
44
|
-
for (const attr in childNode.attribs) {
|
|
45
|
-
const value = childNode.attribs[attr];
|
|
46
|
-
switch (attr) {
|
|
47
|
-
case "rx":
|
|
48
|
-
case "ry":
|
|
49
|
-
case "x":
|
|
50
|
-
case "y":
|
|
51
|
-
if (value === "0") {
|
|
52
|
-
delete attribs[attr];
|
|
53
|
-
}
|
|
54
|
-
break;
|
|
55
|
-
case "transform":
|
|
56
|
-
if (value === "") {
|
|
57
|
-
delete attribs[attr];
|
|
58
|
-
}
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
55
|
break;
|
|
63
56
|
}
|
|
64
57
|
default:
|
|
@@ -95,6 +88,58 @@ function remove(svg) {
|
|
|
95
88
|
unwrapEmptyGroup(svg);
|
|
96
89
|
let content = svg.toString();
|
|
97
90
|
const backup = content;
|
|
91
|
+
const isPenpot = content.includes("frame-clip-def");
|
|
92
|
+
if (isPenpot) {
|
|
93
|
+
cleanupInlineStyle(svg);
|
|
94
|
+
parseSVG(svg, (item) => {
|
|
95
|
+
const tagName = item.tagName;
|
|
96
|
+
for (const attr in item.element.attribs) {
|
|
97
|
+
const value = item.element.attribs[attr];
|
|
98
|
+
switch (attr) {
|
|
99
|
+
case "id":
|
|
100
|
+
if (!maskTags.has(tagName) && !symbolTag.has(tagName)) {
|
|
101
|
+
item.$element.removeAttr(attr);
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
case "class":
|
|
105
|
+
case "xmlns:xlink":
|
|
106
|
+
case "version":
|
|
107
|
+
item.$element.removeAttr(attr);
|
|
108
|
+
break;
|
|
109
|
+
case "transform": {
|
|
110
|
+
const trimmed = value.replace(/\s+/g, "").replace(/\.0+/g, "");
|
|
111
|
+
if (!trimmed || trimmed === "matrix(1,0,0,1,0,0)") {
|
|
112
|
+
item.$element.removeAttr(attr);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "rx":
|
|
117
|
+
case "ry":
|
|
118
|
+
case "x":
|
|
119
|
+
case "y":
|
|
120
|
+
if (value === "0") {
|
|
121
|
+
item.$element.removeAttr(attr);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case "fill-opacity":
|
|
125
|
+
case "stroke-opacity":
|
|
126
|
+
case "opacity":
|
|
127
|
+
if (value === "1") {
|
|
128
|
+
item.$element.removeAttr(attr);
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
case "fill":
|
|
132
|
+
case "stroke": {
|
|
133
|
+
const colorValue = stringToColor(value);
|
|
134
|
+
if (colorValue?.type === "rgb") {
|
|
135
|
+
item.$element.attr(attr, colorToString(colorValue));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
content = svg.toString();
|
|
142
|
+
}
|
|
98
143
|
const clipPathBlocks = content.match(
|
|
99
144
|
/<clipPath[^>]*>[\s\S]+?<\/clipPath>/g
|
|
100
145
|
);
|
|
@@ -103,7 +148,6 @@ function remove(svg) {
|
|
|
103
148
|
const lines = content.split(split);
|
|
104
149
|
content = lines.shift() + split + lines.join("");
|
|
105
150
|
}
|
|
106
|
-
content = content.replaceAll('class="frame-clip-def frame-clip"', "");
|
|
107
151
|
if (content.includes("<defs>")) {
|
|
108
152
|
content = content.replace(/<\/?defs>/g, "");
|
|
109
153
|
}
|
|
@@ -136,30 +180,21 @@ function remove(svg) {
|
|
|
136
180
|
if (typeof clipID !== "string") {
|
|
137
181
|
return false;
|
|
138
182
|
}
|
|
139
|
-
const checkClipPath = (node) => {
|
|
140
|
-
const id = node.attribs["id"];
|
|
141
|
-
if (id !== clipID) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const result = checkClipPathNode(
|
|
145
|
-
node,
|
|
146
|
-
svg.viewBox.width,
|
|
147
|
-
svg.viewBox.height
|
|
148
|
-
);
|
|
149
|
-
cheerio(node).remove();
|
|
150
|
-
return result;
|
|
151
|
-
};
|
|
152
183
|
const findClipPath = () => {
|
|
153
184
|
for (let i = 0; i < children.length; i++) {
|
|
154
185
|
const node = children[i];
|
|
155
|
-
if (node.type === "tag") {
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
158
|
-
const result =
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
186
|
+
if (node.type === "tag" && node.tagName === "clipPath") {
|
|
187
|
+
const id = node.attribs["id"];
|
|
188
|
+
if (id === clipID) {
|
|
189
|
+
const result = checkClipPathNode(
|
|
190
|
+
node,
|
|
191
|
+
svg.viewBox.width,
|
|
192
|
+
svg.viewBox.height
|
|
193
|
+
);
|
|
194
|
+
cheerio(node).remove();
|
|
195
|
+
return result;
|
|
162
196
|
}
|
|
197
|
+
return;
|
|
163
198
|
}
|
|
164
199
|
}
|
|
165
200
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Collection of functions for cleaning up and parsing SVG for Iconify project",
|
|
5
5
|
"author": "Vjacheslav Trushkin",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.2",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"bugs": "https://github.com/iconify/tools/issues",
|
|
9
9
|
"homepage": "https://github.com/iconify/tools",
|