@iconify/tools 3.0.5 → 4.0.0-beta.1
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/colors/detect.cjs +1 -1
- package/lib/colors/detect.d.ts +1 -0
- package/lib/colors/detect.mjs +2 -2
- package/lib/colors/parse.cjs +131 -275
- package/lib/colors/parse.d.ts +8 -15
- package/lib/colors/parse.mjs +135 -278
- package/lib/colors/validate.cjs +2 -11
- package/lib/colors/validate.d.ts +5 -11
- package/lib/colors/validate.mjs +4 -12
- package/lib/export/directory.d.ts +1 -0
- package/lib/export/icon-package.d.ts +4 -1
- package/lib/export/json-package.cjs +1 -0
- package/lib/export/json-package.d.ts +2 -0
- package/lib/export/json-package.mjs +1 -0
- package/lib/icon-set/index.cjs +1 -1
- package/lib/icon-set/index.d.ts +2 -1
- package/lib/icon-set/index.mjs +1 -1
- package/lib/icon-set/match.d.ts +1 -0
- package/lib/icon-set/merge.d.ts +1 -0
- package/lib/icon-set/modified.d.ts +1 -0
- package/lib/icon-set/tags.d.ts +1 -0
- package/lib/import/directory.d.ts +1 -0
- package/lib/import/figma/index.d.ts +1 -0
- package/lib/import/figma/nodes.d.ts +1 -0
- package/lib/import/figma/query.d.ts +1 -0
- package/lib/import/figma/types/nodes.d.ts +1 -0
- package/lib/import/figma/types/options.d.ts +1 -0
- package/lib/import/figma/types/result.d.ts +1 -0
- package/lib/index.cjs +4 -6
- package/lib/index.d.ts +7 -5
- package/lib/index.mjs +6 -5
- package/lib/misc/cheerio.d.ts +4 -2
- package/lib/optimise/figma.cjs +175 -0
- package/lib/optimise/figma.d.ts +11 -0
- package/lib/optimise/figma.mjs +173 -0
- package/lib/optimise/flags.cjs +2 -2
- package/lib/optimise/flags.d.ts +2 -1
- package/lib/optimise/flags.mjs +2 -2
- package/lib/optimise/global-style.cjs +6 -6
- package/lib/optimise/global-style.d.ts +2 -1
- package/lib/optimise/global-style.mjs +6 -6
- package/lib/optimise/mask.cjs +110 -0
- package/lib/optimise/mask.d.ts +24 -0
- package/lib/optimise/mask.mjs +108 -0
- package/lib/optimise/origin.d.ts +1 -0
- package/lib/optimise/scale.d.ts +1 -0
- package/lib/optimise/svgo.d.ts +1 -0
- package/lib/svg/analyse/error.d.ts +2 -0
- package/lib/svg/analyse/types.d.ts +4 -1
- package/lib/svg/analyse.cjs +1 -1
- package/lib/svg/analyse.d.ts +2 -0
- package/lib/svg/analyse.mjs +3 -3
- package/lib/svg/cleanup/attribs.cjs +1 -1
- package/lib/svg/cleanup/attribs.d.ts +1 -0
- package/lib/svg/cleanup/attribs.mjs +2 -2
- package/lib/svg/cleanup/bad-tags.cjs +1 -1
- package/lib/svg/cleanup/bad-tags.d.ts +1 -0
- package/lib/svg/cleanup/bad-tags.mjs +2 -2
- package/lib/svg/cleanup/inline-style.cjs +1 -1
- package/lib/svg/cleanup/inline-style.d.ts +1 -0
- package/lib/svg/cleanup/inline-style.mjs +2 -2
- package/lib/svg/cleanup/root-style.cjs +1 -1
- package/lib/svg/cleanup/root-style.d.ts +1 -0
- package/lib/svg/cleanup/root-style.mjs +2 -2
- package/lib/svg/cleanup/root-svg.d.ts +1 -0
- package/lib/svg/cleanup/svgo-style.cjs +1 -1
- package/lib/svg/cleanup/svgo-style.d.ts +1 -0
- package/lib/svg/cleanup/svgo-style.mjs +2 -2
- package/lib/svg/cleanup.d.ts +1 -0
- package/lib/svg/index.cjs +13 -3
- package/lib/svg/index.d.ts +2 -1
- package/lib/svg/index.mjs +1 -1
- package/lib/svg/parse-style.cjs +178 -235
- package/lib/svg/parse-style.d.ts +4 -9
- package/lib/svg/parse-style.mjs +180 -236
- package/lib/svg/parse.cjs +26 -58
- package/lib/svg/parse.d.ts +4 -10
- package/lib/svg/parse.mjs +27 -58
- package/package.json +25 -13
package/lib/icon-set/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { IconifyIconCustomisations } from '@iconify/utils/lib/customisations/def
|
|
|
3
3
|
import { IconSetIconEntry, IconCategory, IconSetIconType, IconSetAsyncForEachCallback, IconSetSyncForEachCallback, ResolvedIconifyIcon, CommonIconProps, CheckThemeResult } from './types.js';
|
|
4
4
|
import { SVG } from '../svg/index.js';
|
|
5
5
|
import { ParentIconsTree } from '@iconify/utils/lib/icon-set/tree';
|
|
6
|
+
import 'cheerio';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Sort theme keys: long keys first
|
|
@@ -117,7 +118,7 @@ declare class IconSet {
|
|
|
117
118
|
*/
|
|
118
119
|
remove(name: string, removeDependencies?: boolean | string): number;
|
|
119
120
|
/**
|
|
120
|
-
*
|
|
121
|
+
* Rename icon
|
|
121
122
|
*/
|
|
122
123
|
rename(oldName: string, newName: string): boolean;
|
|
123
124
|
/**
|
package/lib/icon-set/index.mjs
CHANGED
package/lib/icon-set/match.d.ts
CHANGED
package/lib/icon-set/merge.d.ts
CHANGED
package/lib/icon-set/tags.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import '@iconify/types';
|
|
|
6
6
|
import '@iconify/utils/lib/customisations/defaults';
|
|
7
7
|
import '../../icon-set/types.js';
|
|
8
8
|
import '../../svg/index.js';
|
|
9
|
+
import 'cheerio';
|
|
9
10
|
import '@iconify/utils/lib/icon-set/tree';
|
|
10
11
|
import './types/nodes.js';
|
|
11
12
|
import './types/api.js';
|
|
@@ -5,6 +5,7 @@ import '@iconify/types';
|
|
|
5
5
|
import '@iconify/utils/lib/customisations/defaults';
|
|
6
6
|
import '../../../icon-set/types.js';
|
|
7
7
|
import '../../../svg/index.js';
|
|
8
|
+
import 'cheerio';
|
|
8
9
|
import '@iconify/utils/lib/icon-set/tree';
|
|
9
10
|
|
|
10
11
|
type FigmaImportParentNodeType = 'CANVAS' | 'FRAME' | 'GROUP' | 'SECTION';
|
package/lib/index.cjs
CHANGED
|
@@ -32,12 +32,13 @@ const colors_parse = require('./colors/parse.cjs');
|
|
|
32
32
|
const colors_validate = require('./colors/validate.cjs');
|
|
33
33
|
const colors_detect = require('./colors/detect.cjs');
|
|
34
34
|
const optimise_svgo = require('./optimise/svgo.cjs');
|
|
35
|
+
const optimise_figma = require('./optimise/figma.cjs');
|
|
35
36
|
const optimise_flags = require('./optimise/flags.cjs');
|
|
36
37
|
const optimise_origin = require('./optimise/origin.cjs');
|
|
38
|
+
const optimise_mask = require('./optimise/mask.cjs');
|
|
37
39
|
const optimise_scale = require('./optimise/scale.cjs');
|
|
38
40
|
const optimise_globalStyle = require('./optimise/global-style.cjs');
|
|
39
41
|
const export_directory = require('./export/directory.cjs');
|
|
40
|
-
const export_iconPackage = require('./export/icon-package.cjs');
|
|
41
42
|
const export_jsonPackage = require('./export/json-package.cjs');
|
|
42
43
|
const misc_writeJson = require('./misc/write-json.cjs');
|
|
43
44
|
const export_helpers_prepare = require('./export/helpers/prepare.cjs');
|
|
@@ -92,9 +93,7 @@ require('./export/helpers/custom-files.cjs');
|
|
|
92
93
|
|
|
93
94
|
exports.SVG = svg_index.SVG;
|
|
94
95
|
exports.parseSVG = svg_parse.parseSVG;
|
|
95
|
-
exports.parseSVGSync = svg_parse.parseSVGSync;
|
|
96
96
|
exports.parseSVGStyle = svg_parseStyle.parseSVGStyle;
|
|
97
|
-
exports.parseSVGStyleSync = svg_parseStyle.parseSVGStyleSync;
|
|
98
97
|
exports.analyseSVGStructure = svg_analyse.analyseSVGStructure;
|
|
99
98
|
exports.cleanupSVG = svg_cleanup.cleanupSVG;
|
|
100
99
|
exports.removeBadAttributes = svg_cleanup_attribs.removeBadAttributes;
|
|
@@ -125,17 +124,16 @@ exports.downloadPackage = download_index.downloadPackage;
|
|
|
125
124
|
exports.downloadFile = download_api_download.downloadFile;
|
|
126
125
|
exports.isEmptyColor = colors_parse.isEmptyColor;
|
|
127
126
|
exports.parseColors = colors_parse.parseColors;
|
|
128
|
-
exports.parseColorsSync = colors_parse.parseColorsSync;
|
|
129
127
|
exports.validateColors = colors_validate.validateColors;
|
|
130
|
-
exports.validateColorsSync = colors_validate.validateColorsSync;
|
|
131
128
|
exports.detectIconSetPalette = colors_detect.detectIconSetPalette;
|
|
132
129
|
exports.runSVGO = optimise_svgo.runSVGO;
|
|
130
|
+
exports.removeFigmaClipPathFromSVG = optimise_figma.removeFigmaClipPathFromSVG;
|
|
133
131
|
exports.deOptimisePaths = optimise_flags.deOptimisePaths;
|
|
134
132
|
exports.resetSVGOrigin = optimise_origin.resetSVGOrigin;
|
|
133
|
+
exports.convertSVGToMask = optimise_mask.convertSVGToMask;
|
|
135
134
|
exports.scaleSVG = optimise_scale.scaleSVG;
|
|
136
135
|
exports.cleanupGlobalStyle = optimise_globalStyle.cleanupGlobalStyle;
|
|
137
136
|
exports.exportToDirectory = export_directory.exportToDirectory;
|
|
138
|
-
exports.exportIconPackage = export_iconPackage.exportIconPackage;
|
|
139
137
|
exports.exportJSONPackage = export_jsonPackage.exportJSONPackage;
|
|
140
138
|
exports.writeJSONFile = misc_writeJson.writeJSONFile;
|
|
141
139
|
exports.prepareDirectoryForExport = export_helpers_prepare.prepareDirectoryForExport;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { SVG } from './svg/index.js';
|
|
2
|
-
export { parseSVG
|
|
3
|
-
export { parseSVGStyle
|
|
2
|
+
export { parseSVG } from './svg/parse.js';
|
|
3
|
+
export { parseSVGStyle } from './svg/parse-style.js';
|
|
4
4
|
export { analyseSVGStructure } from './svg/analyse.js';
|
|
5
5
|
export { cleanupSVG } from './svg/cleanup.js';
|
|
6
6
|
export { removeBadAttributes } from './svg/cleanup/attribs.js';
|
|
@@ -26,16 +26,17 @@ export { downloadNPMPackage } from './download/npm/index.js';
|
|
|
26
26
|
export { getNPMVersion, getPackageVersion } from './download/npm/version.js';
|
|
27
27
|
export { downloadPackage } from './download/index.js';
|
|
28
28
|
export { downloadFile } from './download/api/download.js';
|
|
29
|
-
export { isEmptyColor, parseColors
|
|
30
|
-
export { validateColors
|
|
29
|
+
export { isEmptyColor, parseColors } from './colors/parse.js';
|
|
30
|
+
export { validateColors } from './colors/validate.js';
|
|
31
31
|
export { detectIconSetPalette } from './colors/detect.js';
|
|
32
32
|
export { runSVGO } from './optimise/svgo.js';
|
|
33
|
+
export { removeFigmaClipPathFromSVG } from './optimise/figma.js';
|
|
33
34
|
export { deOptimisePaths } from './optimise/flags.js';
|
|
34
35
|
export { resetSVGOrigin } from './optimise/origin.js';
|
|
36
|
+
export { convertSVGToMask } from './optimise/mask.js';
|
|
35
37
|
export { scaleSVG } from './optimise/scale.js';
|
|
36
38
|
export { cleanupGlobalStyle } from './optimise/global-style.js';
|
|
37
39
|
export { exportToDirectory } from './export/directory.js';
|
|
38
|
-
export { exportIconPackage } from './export/icon-package.js';
|
|
39
40
|
export { exportJSONPackage } from './export/json-package.js';
|
|
40
41
|
export { writeJSONFile } from './misc/write-json.js';
|
|
41
42
|
export { prepareDirectoryForExport } from './export/helpers/prepare.js';
|
|
@@ -47,6 +48,7 @@ export { execAsync } from './misc/exec.js';
|
|
|
47
48
|
export { cleanupIconKeyword } from './misc/keyword.js';
|
|
48
49
|
export { bumpVersion } from './misc/bump-version.js';
|
|
49
50
|
export { sendAPIQuery } from './download/api/index.js';
|
|
51
|
+
import 'cheerio';
|
|
50
52
|
import '@iconify/types';
|
|
51
53
|
import '@iconify/utils/lib/customisations/defaults';
|
|
52
54
|
import './misc/cheerio.js';
|
package/lib/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { SVG } from './svg/index.mjs';
|
|
2
|
-
export { parseSVG
|
|
3
|
-
export { parseSVGStyle
|
|
2
|
+
export { parseSVG } from './svg/parse.mjs';
|
|
3
|
+
export { parseSVGStyle } from './svg/parse-style.mjs';
|
|
4
4
|
export { analyseSVGStructure } from './svg/analyse.mjs';
|
|
5
5
|
export { cleanupSVG } from './svg/cleanup.mjs';
|
|
6
6
|
export { removeBadAttributes } from './svg/cleanup/attribs.mjs';
|
|
@@ -26,16 +26,17 @@ export { downloadNPMPackage } from './download/npm/index.mjs';
|
|
|
26
26
|
export { getNPMVersion, getPackageVersion } from './download/npm/version.mjs';
|
|
27
27
|
export { downloadPackage } from './download/index.mjs';
|
|
28
28
|
export { downloadFile } from './download/api/download.mjs';
|
|
29
|
-
export { isEmptyColor, parseColors
|
|
30
|
-
export { validateColors
|
|
29
|
+
export { isEmptyColor, parseColors } from './colors/parse.mjs';
|
|
30
|
+
export { validateColors } from './colors/validate.mjs';
|
|
31
31
|
export { detectIconSetPalette } from './colors/detect.mjs';
|
|
32
32
|
export { runSVGO } from './optimise/svgo.mjs';
|
|
33
|
+
export { removeFigmaClipPathFromSVG } from './optimise/figma.mjs';
|
|
33
34
|
export { deOptimisePaths } from './optimise/flags.mjs';
|
|
34
35
|
export { resetSVGOrigin } from './optimise/origin.mjs';
|
|
36
|
+
export { convertSVGToMask } from './optimise/mask.mjs';
|
|
35
37
|
export { scaleSVG } from './optimise/scale.mjs';
|
|
36
38
|
export { cleanupGlobalStyle } from './optimise/global-style.mjs';
|
|
37
39
|
export { exportToDirectory } from './export/directory.mjs';
|
|
38
|
-
export { exportIconPackage } from './export/icon-package.mjs';
|
|
39
40
|
export { exportJSONPackage } from './export/json-package.mjs';
|
|
40
41
|
export { writeJSONFile } from './misc/write-json.mjs';
|
|
41
42
|
export { prepareDirectoryForExport } from './export/helpers/prepare.mjs';
|
package/lib/misc/cheerio.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import * as cheerio from 'cheerio';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Shortcuts for Cheerio elements
|
|
3
5
|
*/
|
|
4
|
-
type CheerioElement = cheerio.
|
|
5
|
-
type WrappedCheerioElement = cheerio.Cheerio
|
|
6
|
+
type CheerioElement = cheerio.Element;
|
|
7
|
+
type WrappedCheerioElement = cheerio.Cheerio<cheerio.Element>;
|
|
6
8
|
|
|
7
9
|
export { CheerioElement, WrappedCheerioElement };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const svg_data_tags = require('../svg/data/tags.cjs');
|
|
4
|
+
|
|
5
|
+
function isTinyNumber(value, limit) {
|
|
6
|
+
const num = parseInt(value);
|
|
7
|
+
return !isNaN(num) && Math.abs(num) < limit;
|
|
8
|
+
}
|
|
9
|
+
function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
10
|
+
for (const attr in clipNode.attribs) {
|
|
11
|
+
if (attr !== "id") {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const children = clipNode.children.filter((node) => node.type !== "text");
|
|
16
|
+
if (children.length !== 1) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const childNode = children[0];
|
|
20
|
+
if (childNode.type !== "tag" || childNode.children.length) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const attribs = {
|
|
24
|
+
...childNode.attribs
|
|
25
|
+
};
|
|
26
|
+
delete attribs["fill"];
|
|
27
|
+
const fill = (childNode.attribs["fill"] ?? "").toLowerCase();
|
|
28
|
+
if (fill !== "white" && fill !== "#fff" && fill !== "#ffffff") {
|
|
29
|
+
console.warn(
|
|
30
|
+
"Unxepected fill on clip path:",
|
|
31
|
+
childNode.attribs["fill"]
|
|
32
|
+
);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
switch (childNode.tagName) {
|
|
36
|
+
case "rect": {
|
|
37
|
+
const width = parseInt(childNode.attribs["width"]);
|
|
38
|
+
const height = parseInt(childNode.attribs["height"]);
|
|
39
|
+
if (width !== expectedWidth || height !== expectedHeight) {
|
|
40
|
+
console.warn("Invalid size of clip path");
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
delete attribs["width"];
|
|
44
|
+
delete attribs["height"];
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
default:
|
|
48
|
+
console.warn(
|
|
49
|
+
"Unexpected tag in Figma clip path:",
|
|
50
|
+
childNode.tagName
|
|
51
|
+
);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
Object.keys(attribs).forEach((attr) => {
|
|
55
|
+
const value = attribs[attr];
|
|
56
|
+
switch (attr) {
|
|
57
|
+
case "transform": {
|
|
58
|
+
const translateStart = "translate(";
|
|
59
|
+
const translateEnd = ")";
|
|
60
|
+
if (value.startsWith(translateStart) && value.endsWith(translateEnd)) {
|
|
61
|
+
const translateParts = value.slice(translateStart.length, 0 - translateEnd.length).split(/\s+/);
|
|
62
|
+
const limit = Math.min(expectedWidth, expectedHeight) / 1e3;
|
|
63
|
+
if (translateParts.length === 2 && isTinyNumber(translateParts[0], limit) && isTinyNumber(translateParts[1], limit)) {
|
|
64
|
+
delete attribs[attr];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
node: clipNode,
|
|
72
|
+
attribs
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const urlStart = "url(#";
|
|
76
|
+
const urlEnd = ")";
|
|
77
|
+
function removeFigmaClipPathFromSVG(svg) {
|
|
78
|
+
const cheerio = svg.$svg;
|
|
79
|
+
const $root = svg.$svg(":root");
|
|
80
|
+
const children = $root.children();
|
|
81
|
+
const backup = svg.toString();
|
|
82
|
+
const shapesToClip = [];
|
|
83
|
+
let clipID;
|
|
84
|
+
for (let i = 0; i < children.length; i++) {
|
|
85
|
+
const node = children[i];
|
|
86
|
+
if (node.type === "tag") {
|
|
87
|
+
const tagName = node.tagName;
|
|
88
|
+
if (!svg_data_tags.defsTag.has(tagName) && !svg_data_tags.maskTags.has(tagName) && !svg_data_tags.symbolTag.has(tagName)) {
|
|
89
|
+
const clipPath2 = node.attribs["clip-path"];
|
|
90
|
+
if (!clipPath2 || !clipPath2.startsWith(urlStart) || !clipPath2.endsWith(urlEnd)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const id = clipPath2.slice(urlStart.length, 0 - urlEnd.length);
|
|
94
|
+
if (typeof clipID === "string" && clipID !== id) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
clipID = id;
|
|
98
|
+
shapesToClip.push(node);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (typeof clipID !== "string") {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const checkClipPath = (node) => {
|
|
106
|
+
const id = node.attribs["id"];
|
|
107
|
+
if (id !== clipID) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const result = checkClipPathNode(
|
|
111
|
+
node,
|
|
112
|
+
svg.viewBox.width,
|
|
113
|
+
svg.viewBox.height
|
|
114
|
+
);
|
|
115
|
+
cheerio(node).remove();
|
|
116
|
+
return result;
|
|
117
|
+
};
|
|
118
|
+
const findClipPath = () => {
|
|
119
|
+
for (let i = 0; i < children.length; i++) {
|
|
120
|
+
const node = children[i];
|
|
121
|
+
if (node.type === "tag") {
|
|
122
|
+
const tagName = node.tagName;
|
|
123
|
+
if (svg_data_tags.defsTag.has(tagName)) {
|
|
124
|
+
const defsChildren = node.children;
|
|
125
|
+
for (let j = 0; j < defsChildren.length; j++) {
|
|
126
|
+
const childNode = defsChildren[j];
|
|
127
|
+
if (childNode.type === "tag" && childNode.tagName === "clipPath") {
|
|
128
|
+
const result = checkClipPath(childNode);
|
|
129
|
+
if (result !== void 0) {
|
|
130
|
+
const validChildren = node.children.filter(
|
|
131
|
+
(test) => {
|
|
132
|
+
if (test.type === "text") {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
if (!validChildren.length) {
|
|
139
|
+
cheerio(node).remove();
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (tagName === "clipPath") {
|
|
147
|
+
const result = checkClipPath(node);
|
|
148
|
+
if (result !== void 0) {
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const clipPath = findClipPath();
|
|
156
|
+
if (!clipPath) {
|
|
157
|
+
svg.load(backup);
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const attribs = clipPath.attribs;
|
|
161
|
+
for (let i = 0; i < shapesToClip.length; i++) {
|
|
162
|
+
const node = shapesToClip[i];
|
|
163
|
+
cheerio(node).removeAttr("clip-path");
|
|
164
|
+
for (const attr in attribs) {
|
|
165
|
+
if (node.attribs[attr] !== void 0) {
|
|
166
|
+
svg.load(backup);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
cheerio(node).attr(attr, attribs[attr]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
exports.removeFigmaClipPathFromSVG = removeFigmaClipPathFromSVG;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SVG } from '../svg/index.js';
|
|
2
|
+
import 'cheerio';
|
|
3
|
+
import '@iconify/types';
|
|
4
|
+
import '@iconify/utils/lib/customisations/defaults';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Removes clip path from SVG, which Figma adds to icons that might have overflowing elements
|
|
8
|
+
*/
|
|
9
|
+
declare function removeFigmaClipPathFromSVG(svg: SVG): boolean;
|
|
10
|
+
|
|
11
|
+
export { removeFigmaClipPathFromSVG };
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { defsTag, maskTags, symbolTag } from '../svg/data/tags.mjs';
|
|
2
|
+
|
|
3
|
+
function isTinyNumber(value, limit) {
|
|
4
|
+
const num = parseInt(value);
|
|
5
|
+
return !isNaN(num) && Math.abs(num) < limit;
|
|
6
|
+
}
|
|
7
|
+
function checkClipPathNode(clipNode, expectedWidth, expectedHeight) {
|
|
8
|
+
for (const attr in clipNode.attribs) {
|
|
9
|
+
if (attr !== "id") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const children = clipNode.children.filter((node) => node.type !== "text");
|
|
14
|
+
if (children.length !== 1) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const childNode = children[0];
|
|
18
|
+
if (childNode.type !== "tag" || childNode.children.length) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const attribs = {
|
|
22
|
+
...childNode.attribs
|
|
23
|
+
};
|
|
24
|
+
delete attribs["fill"];
|
|
25
|
+
const fill = (childNode.attribs["fill"] ?? "").toLowerCase();
|
|
26
|
+
if (fill !== "white" && fill !== "#fff" && fill !== "#ffffff") {
|
|
27
|
+
console.warn(
|
|
28
|
+
"Unxepected fill on clip path:",
|
|
29
|
+
childNode.attribs["fill"]
|
|
30
|
+
);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
switch (childNode.tagName) {
|
|
34
|
+
case "rect": {
|
|
35
|
+
const width = parseInt(childNode.attribs["width"]);
|
|
36
|
+
const height = parseInt(childNode.attribs["height"]);
|
|
37
|
+
if (width !== expectedWidth || height !== expectedHeight) {
|
|
38
|
+
console.warn("Invalid size of clip path");
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
delete attribs["width"];
|
|
42
|
+
delete attribs["height"];
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
default:
|
|
46
|
+
console.warn(
|
|
47
|
+
"Unexpected tag in Figma clip path:",
|
|
48
|
+
childNode.tagName
|
|
49
|
+
);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
Object.keys(attribs).forEach((attr) => {
|
|
53
|
+
const value = attribs[attr];
|
|
54
|
+
switch (attr) {
|
|
55
|
+
case "transform": {
|
|
56
|
+
const translateStart = "translate(";
|
|
57
|
+
const translateEnd = ")";
|
|
58
|
+
if (value.startsWith(translateStart) && value.endsWith(translateEnd)) {
|
|
59
|
+
const translateParts = value.slice(translateStart.length, 0 - translateEnd.length).split(/\s+/);
|
|
60
|
+
const limit = Math.min(expectedWidth, expectedHeight) / 1e3;
|
|
61
|
+
if (translateParts.length === 2 && isTinyNumber(translateParts[0], limit) && isTinyNumber(translateParts[1], limit)) {
|
|
62
|
+
delete attribs[attr];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
node: clipNode,
|
|
70
|
+
attribs
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const urlStart = "url(#";
|
|
74
|
+
const urlEnd = ")";
|
|
75
|
+
function removeFigmaClipPathFromSVG(svg) {
|
|
76
|
+
const cheerio = svg.$svg;
|
|
77
|
+
const $root = svg.$svg(":root");
|
|
78
|
+
const children = $root.children();
|
|
79
|
+
const backup = svg.toString();
|
|
80
|
+
const shapesToClip = [];
|
|
81
|
+
let clipID;
|
|
82
|
+
for (let i = 0; i < children.length; i++) {
|
|
83
|
+
const node = children[i];
|
|
84
|
+
if (node.type === "tag") {
|
|
85
|
+
const tagName = node.tagName;
|
|
86
|
+
if (!defsTag.has(tagName) && !maskTags.has(tagName) && !symbolTag.has(tagName)) {
|
|
87
|
+
const clipPath2 = node.attribs["clip-path"];
|
|
88
|
+
if (!clipPath2 || !clipPath2.startsWith(urlStart) || !clipPath2.endsWith(urlEnd)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const id = clipPath2.slice(urlStart.length, 0 - urlEnd.length);
|
|
92
|
+
if (typeof clipID === "string" && clipID !== id) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
clipID = id;
|
|
96
|
+
shapesToClip.push(node);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (typeof clipID !== "string") {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const checkClipPath = (node) => {
|
|
104
|
+
const id = node.attribs["id"];
|
|
105
|
+
if (id !== clipID) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const result = checkClipPathNode(
|
|
109
|
+
node,
|
|
110
|
+
svg.viewBox.width,
|
|
111
|
+
svg.viewBox.height
|
|
112
|
+
);
|
|
113
|
+
cheerio(node).remove();
|
|
114
|
+
return result;
|
|
115
|
+
};
|
|
116
|
+
const findClipPath = () => {
|
|
117
|
+
for (let i = 0; i < children.length; i++) {
|
|
118
|
+
const node = children[i];
|
|
119
|
+
if (node.type === "tag") {
|
|
120
|
+
const tagName = node.tagName;
|
|
121
|
+
if (defsTag.has(tagName)) {
|
|
122
|
+
const defsChildren = node.children;
|
|
123
|
+
for (let j = 0; j < defsChildren.length; j++) {
|
|
124
|
+
const childNode = defsChildren[j];
|
|
125
|
+
if (childNode.type === "tag" && childNode.tagName === "clipPath") {
|
|
126
|
+
const result = checkClipPath(childNode);
|
|
127
|
+
if (result !== void 0) {
|
|
128
|
+
const validChildren = node.children.filter(
|
|
129
|
+
(test) => {
|
|
130
|
+
if (test.type === "text") {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
if (!validChildren.length) {
|
|
137
|
+
cheerio(node).remove();
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (tagName === "clipPath") {
|
|
145
|
+
const result = checkClipPath(node);
|
|
146
|
+
if (result !== void 0) {
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const clipPath = findClipPath();
|
|
154
|
+
if (!clipPath) {
|
|
155
|
+
svg.load(backup);
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const attribs = clipPath.attribs;
|
|
159
|
+
for (let i = 0; i < shapesToClip.length; i++) {
|
|
160
|
+
const node = shapesToClip[i];
|
|
161
|
+
cheerio(node).removeAttr("clip-path");
|
|
162
|
+
for (const attr in attribs) {
|
|
163
|
+
if (node.attribs[attr] !== void 0) {
|
|
164
|
+
svg.load(backup);
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
cheerio(node).attr(attr, attribs[attr]);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { removeFigmaClipPathFromSVG };
|
package/lib/optimise/flags.cjs
CHANGED
|
@@ -235,8 +235,8 @@ function cleanPath(path) {
|
|
|
235
235
|
});
|
|
236
236
|
return output;
|
|
237
237
|
}
|
|
238
|
-
|
|
239
|
-
|
|
238
|
+
function deOptimisePaths(svg) {
|
|
239
|
+
svg_parse.parseSVG(svg, (item) => {
|
|
240
240
|
if (item.tagName !== "path") {
|
|
241
241
|
return;
|
|
242
242
|
}
|
package/lib/optimise/flags.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { SVG } from '../svg/index.js';
|
|
2
|
+
import 'cheerio';
|
|
2
3
|
import '@iconify/types';
|
|
3
4
|
import '@iconify/utils/lib/customisations/defaults';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* De-optimise paths. Compressed paths are still not supported by some software.
|
|
7
8
|
*/
|
|
8
|
-
declare function deOptimisePaths(svg: SVG):
|
|
9
|
+
declare function deOptimisePaths(svg: SVG): void;
|
|
9
10
|
|
|
10
11
|
export { deOptimisePaths };
|
package/lib/optimise/flags.mjs
CHANGED
|
@@ -233,8 +233,8 @@ function cleanPath(path) {
|
|
|
233
233
|
});
|
|
234
234
|
return output;
|
|
235
235
|
}
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
function deOptimisePaths(svg) {
|
|
237
|
+
parseSVG(svg, (item) => {
|
|
238
238
|
if (item.tagName !== "path") {
|
|
239
239
|
return;
|
|
240
240
|
}
|