@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.
Files changed (79) hide show
  1. package/lib/colors/detect.cjs +1 -1
  2. package/lib/colors/detect.d.ts +1 -0
  3. package/lib/colors/detect.mjs +2 -2
  4. package/lib/colors/parse.cjs +131 -275
  5. package/lib/colors/parse.d.ts +8 -15
  6. package/lib/colors/parse.mjs +135 -278
  7. package/lib/colors/validate.cjs +2 -11
  8. package/lib/colors/validate.d.ts +5 -11
  9. package/lib/colors/validate.mjs +4 -12
  10. package/lib/export/directory.d.ts +1 -0
  11. package/lib/export/icon-package.d.ts +4 -1
  12. package/lib/export/json-package.cjs +1 -0
  13. package/lib/export/json-package.d.ts +2 -0
  14. package/lib/export/json-package.mjs +1 -0
  15. package/lib/icon-set/index.cjs +1 -1
  16. package/lib/icon-set/index.d.ts +2 -1
  17. package/lib/icon-set/index.mjs +1 -1
  18. package/lib/icon-set/match.d.ts +1 -0
  19. package/lib/icon-set/merge.d.ts +1 -0
  20. package/lib/icon-set/modified.d.ts +1 -0
  21. package/lib/icon-set/tags.d.ts +1 -0
  22. package/lib/import/directory.d.ts +1 -0
  23. package/lib/import/figma/index.d.ts +1 -0
  24. package/lib/import/figma/nodes.d.ts +1 -0
  25. package/lib/import/figma/query.d.ts +1 -0
  26. package/lib/import/figma/types/nodes.d.ts +1 -0
  27. package/lib/import/figma/types/options.d.ts +1 -0
  28. package/lib/import/figma/types/result.d.ts +1 -0
  29. package/lib/index.cjs +4 -6
  30. package/lib/index.d.ts +7 -5
  31. package/lib/index.mjs +6 -5
  32. package/lib/misc/cheerio.d.ts +4 -2
  33. package/lib/optimise/figma.cjs +175 -0
  34. package/lib/optimise/figma.d.ts +11 -0
  35. package/lib/optimise/figma.mjs +173 -0
  36. package/lib/optimise/flags.cjs +2 -2
  37. package/lib/optimise/flags.d.ts +2 -1
  38. package/lib/optimise/flags.mjs +2 -2
  39. package/lib/optimise/global-style.cjs +6 -6
  40. package/lib/optimise/global-style.d.ts +2 -1
  41. package/lib/optimise/global-style.mjs +6 -6
  42. package/lib/optimise/mask.cjs +110 -0
  43. package/lib/optimise/mask.d.ts +24 -0
  44. package/lib/optimise/mask.mjs +108 -0
  45. package/lib/optimise/origin.d.ts +1 -0
  46. package/lib/optimise/scale.d.ts +1 -0
  47. package/lib/optimise/svgo.d.ts +1 -0
  48. package/lib/svg/analyse/error.d.ts +2 -0
  49. package/lib/svg/analyse/types.d.ts +4 -1
  50. package/lib/svg/analyse.cjs +1 -1
  51. package/lib/svg/analyse.d.ts +2 -0
  52. package/lib/svg/analyse.mjs +3 -3
  53. package/lib/svg/cleanup/attribs.cjs +1 -1
  54. package/lib/svg/cleanup/attribs.d.ts +1 -0
  55. package/lib/svg/cleanup/attribs.mjs +2 -2
  56. package/lib/svg/cleanup/bad-tags.cjs +1 -1
  57. package/lib/svg/cleanup/bad-tags.d.ts +1 -0
  58. package/lib/svg/cleanup/bad-tags.mjs +2 -2
  59. package/lib/svg/cleanup/inline-style.cjs +1 -1
  60. package/lib/svg/cleanup/inline-style.d.ts +1 -0
  61. package/lib/svg/cleanup/inline-style.mjs +2 -2
  62. package/lib/svg/cleanup/root-style.cjs +1 -1
  63. package/lib/svg/cleanup/root-style.d.ts +1 -0
  64. package/lib/svg/cleanup/root-style.mjs +2 -2
  65. package/lib/svg/cleanup/root-svg.d.ts +1 -0
  66. package/lib/svg/cleanup/svgo-style.cjs +1 -1
  67. package/lib/svg/cleanup/svgo-style.d.ts +1 -0
  68. package/lib/svg/cleanup/svgo-style.mjs +2 -2
  69. package/lib/svg/cleanup.d.ts +1 -0
  70. package/lib/svg/index.cjs +13 -3
  71. package/lib/svg/index.d.ts +2 -1
  72. package/lib/svg/index.mjs +1 -1
  73. package/lib/svg/parse-style.cjs +178 -235
  74. package/lib/svg/parse-style.d.ts +4 -9
  75. package/lib/svg/parse-style.mjs +180 -236
  76. package/lib/svg/parse.cjs +26 -58
  77. package/lib/svg/parse.d.ts +4 -10
  78. package/lib/svg/parse.mjs +27 -58
  79. package/package.json +25 -13
@@ -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
- * Remove icon
121
+ * Rename icon
121
122
  */
122
123
  rename(oldName: string, newName: string): boolean;
123
124
  /**
@@ -510,7 +510,7 @@ class IconSet {
510
510
  return count;
511
511
  }
512
512
  /**
513
- * Remove icon
513
+ * Rename icon
514
514
  */
515
515
  rename(oldName, newName) {
516
516
  const entries = this.entries;
@@ -4,6 +4,7 @@ import '@iconify/types';
4
4
  import '@iconify/utils/lib/customisations/defaults';
5
5
  import './types.js';
6
6
  import '../svg/index.js';
7
+ import 'cheerio';
7
8
  import '@iconify/utils/lib/icon-set/tree';
8
9
 
9
10
  /**
@@ -3,6 +3,7 @@ import '@iconify/types';
3
3
  import '@iconify/utils/lib/customisations/defaults';
4
4
  import './types.js';
5
5
  import '../svg/index.js';
6
+ import 'cheerio';
6
7
  import '@iconify/utils/lib/icon-set/tree';
7
8
 
8
9
  /**
@@ -3,6 +3,7 @@ import '@iconify/types';
3
3
  import '@iconify/utils/lib/customisations/defaults';
4
4
  import './types.js';
5
5
  import '../svg/index.js';
6
+ import 'cheerio';
6
7
  import '@iconify/utils/lib/icon-set/tree';
7
8
 
8
9
  /**
@@ -3,6 +3,7 @@ import '@iconify/types';
3
3
  import '@iconify/utils/lib/customisations/defaults';
4
4
  import './types.js';
5
5
  import '../svg/index.js';
6
+ import 'cheerio';
6
7
  import '@iconify/utils/lib/icon-set/tree';
7
8
 
8
9
  declare const paletteTags: {
@@ -4,6 +4,7 @@ import '@iconify/types';
4
4
  import '@iconify/utils/lib/customisations/defaults';
5
5
  import '../icon-set/types.js';
6
6
  import '../svg/index.js';
7
+ import 'cheerio';
7
8
  import '@iconify/utils/lib/icon-set/tree';
8
9
  import '../svg/cleanup/bad-tags.js';
9
10
 
@@ -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';
@@ -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
 
@@ -8,6 +8,7 @@ import '@iconify/types';
8
8
  import '@iconify/utils/lib/customisations/defaults';
9
9
  import '../../icon-set/types.js';
10
10
  import '../../svg/index.js';
11
+ import 'cheerio';
11
12
  import '@iconify/utils/lib/icon-set/tree';
12
13
  import './types/nodes.js';
13
14
 
@@ -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';
@@ -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
  import './api.js';
10
11
 
@@ -3,6 +3,7 @@ import '@iconify/types';
3
3
  import '@iconify/utils/lib/customisations/defaults';
4
4
  import '../../../icon-set/types.js';
5
5
  import '../../../svg/index.js';
6
+ import 'cheerio';
6
7
  import '@iconify/utils/lib/icon-set/tree';
7
8
 
8
9
  /**
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, parseSVGSync } from './svg/parse.js';
3
- export { parseSVGStyle, parseSVGStyleSync } from './svg/parse-style.js';
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, parseColorsSync } from './colors/parse.js';
30
- export { validateColors, validateColorsSync } from './colors/validate.js';
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, parseSVGSync } from './svg/parse.mjs';
3
- export { parseSVGStyle, parseSVGStyleSync } from './svg/parse-style.mjs';
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, parseColorsSync } from './colors/parse.mjs';
30
- export { validateColors, validateColorsSync } from './colors/validate.mjs';
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';
@@ -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.TagElement;
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 };
@@ -235,8 +235,8 @@ function cleanPath(path) {
235
235
  });
236
236
  return output;
237
237
  }
238
- async function deOptimisePaths(svg) {
239
- await svg_parse.parseSVG(svg, (item) => {
238
+ function deOptimisePaths(svg) {
239
+ svg_parse.parseSVG(svg, (item) => {
240
240
  if (item.tagName !== "path") {
241
241
  return;
242
242
  }
@@ -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): Promise<void>;
9
+ declare function deOptimisePaths(svg: SVG): void;
9
10
 
10
11
  export { deOptimisePaths };
@@ -233,8 +233,8 @@ function cleanPath(path) {
233
233
  });
234
234
  return output;
235
235
  }
236
- async function deOptimisePaths(svg) {
237
- await parseSVG(svg, (item) => {
236
+ function deOptimisePaths(svg) {
237
+ parseSVG(svg, (item) => {
238
238
  if (item.tagName !== "path") {
239
239
  return;
240
240
  }