vite-awesome-svg-loader 1.3.5 → 1.4.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/index.d.ts CHANGED
@@ -48,6 +48,19 @@ export interface SvgLoaderOptions {
48
48
  * This also can be done in an import: `import imageSrc from "./path/to/image.svg?preserve-line-width"`.
49
49
  */
50
50
  preserveLineWidthList: (string | RegExp)[];
51
+ /**
52
+ * A list of files or directories to disable preserving line width of. Overrides {@link preserveLineWidthList}.
53
+ */
54
+ skipPreserveLineWidthList: (string | RegExp)[];
55
+ /**
56
+ * A list of CSS selectors to disable {@link preserveLineWidthList} for. Use it to leave specific elements stroke
57
+ * width as-is.
58
+ *
59
+ * Can be a list of selectors or selectors-per-files specifiers.
60
+ *
61
+ * Unlike {@link skipSetCurrentColorSelectors} and {@link skipTransformsSelectors}, doesn't impact build performance.
62
+ */
63
+ skipPreserveLineWidthSelectors: (string | SelectorsPerFiles)[];
51
64
  /**
52
65
  * A list of files or directories to replace fill, stroke and `<stop>` colors to `currentColor` of, i.e.:
53
66
  *
@@ -65,6 +78,39 @@ export interface SvgLoaderOptions {
65
78
  * This also can be done in an import: `import imageSrc from "./path/to/image.svg?set-current-color"`.
66
79
  */
67
80
  setCurrentColorList: (string | RegExp)[];
81
+ /**
82
+ * A list of files or directories to disable setting current color of. Overrides {@link setCurrentColorList}.
83
+ */
84
+ skipSetCurrentColorList: (string | RegExp)[];
85
+ /**
86
+ * A list of CSS selectors to disable {@link setCurrentColorList} for. Use it to leave specific elements colors as-is.
87
+ *
88
+ * Can be a list of selectors or selectors-per-files specifiers.
89
+ *
90
+ * **You probably don't need this option.**
91
+ *
92
+ * For example, if you're creating multi-colored icons, consider following:
93
+ *
94
+ * 1. Using SVG-symbols
95
+ * 1. Add data-attributes for different colors: `data-color-primary`, `data-color-secondary` or whatever fits your
96
+ * needs.
97
+ * 1. Colorize icon with CSS:
98
+ *
99
+ * ```css
100
+ * svg *[data-color-primary] {
101
+ * color: var(--icon-color-primary);
102
+ * }
103
+ *
104
+ * svg *[data-color-secondary] {
105
+ * color: var(--icon-color-secondary);
106
+ * }
107
+ * ```
108
+ *
109
+ * This way you'll get full extensibility.
110
+ *
111
+ * **Heavy usage may significantly slow down build time.** Limit selectors to specific files to improve performance.
112
+ */
113
+ skipSetCurrentColorSelectors: (string | SelectorsPerFiles)[];
68
114
  /**
69
115
  * A list of files to skip while transforming.
70
116
  *
@@ -74,6 +120,17 @@ export interface SvgLoaderOptions {
74
120
  * SVGO is still applied to the added files.
75
121
  */
76
122
  skipTransformsList: (string | RegExp)[];
123
+ /**
124
+ * A list of CSS selectors to disable all transforms for. Use it to leave specific elements as-is.
125
+ *
126
+ * Can be a list of selectors or selectors-per-files specifiers.
127
+ *
128
+ * You probably don't need this option. Try rethinking how you manage your assets (see example at
129
+ * {@link skipSetCurrentColorSelectors}). This option is for some very obscure edge cases only.
130
+ *
131
+ * **Heavy usage may significantly slow down build time.** Limit selectors to specific files to improve performance.
132
+ */
133
+ skipTransformsSelectors: (string | SelectorsPerFiles)[];
77
134
  /**
78
135
  * A list of files to skip loading of. Useful for passing original files to another loader.
79
136
  *
@@ -106,6 +163,19 @@ export interface SvgLoaderOptions {
106
163
  */
107
164
  defaultImport: ImportType;
108
165
  }
166
+ /**
167
+ * CSS selector per file or files
168
+ */
169
+ export interface SelectorsPerFiles {
170
+ /**
171
+ * List of filenames and/or paths matchers
172
+ */
173
+ files: (string | RegExp)[];
174
+ /**
175
+ * List of selectors
176
+ */
177
+ selectors: string[];
178
+ }
109
179
  /**
110
180
  * A Vite plugin that:
111
181
  *
@@ -115,8 +185,11 @@ export interface SvgLoaderOptions {
115
185
  * 1. Source code data URI: `import imageSrcDataUri from "./path/to/image.svg?source-data-uri"`.
116
186
  * 1. Source code Base64: `import imageBase64 from "./path/to/image.svg?base64"`.
117
187
  * 1. Source code Base64 data URI: `import imageBase64DataUri from "./path/to/image.svg?base64-data-uri"`.
118
- * 1. Can preserve line width (make icons and line art have same line width when scaling): `import imageSrc from "./path/to/image.svg?preserve-line-width"`. See also: {@link SvgLoaderOptions.preserveLineWidthList}.
119
- * 1. Can replace colors with `currentColor`: `import imageSrc from "./path/to/image.svg?set-current-color"`. See also: {@link SvgLoaderOptions.setCurrentColorList}.
188
+ * 1. Can preserve line width (make icons and line art have same line width when scaling):
189
+ * `import imageSrc from "./path/to/image.svg?preserve-line-width"`.
190
+ * See also: {@link SvgLoaderOptions.preserveLineWidthList}.
191
+ * 1. Can replace colors with `currentColor`: `import imageSrc from "./path/to/image.svg?set-current-color"`.
192
+ * See also: {@link SvgLoaderOptions.setCurrentColorList}.
120
193
  * 1. Will minimize your SVGs using [SVGO](https://github.com/svg/svgo).
121
194
  *
122
195
  * Parameters can be chained with an `&` symbol like in a normal URL:
@@ -147,7 +220,8 @@ export interface SvgLoaderOptions {
147
220
  * import image from "./path/to/image.svg?skip-awesome-svg-loader";
148
221
  * ```
149
222
  *
150
- * You can set filenames and regexes in {@link SvgLoaderOptions}, so you don't have to write such long urls for every import.
223
+ * You can set filenames and regexes in {@link SvgLoaderOptions}, so you don't have to write such long urls for every
224
+ * import.
151
225
  *
152
226
  * @param options Plugin options
153
227
  */
package/index.js CHANGED
@@ -42,22 +42,28 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
42
42
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
43
43
 
44
44
  // src/index.ts
45
- var src_exports = {};
46
- __export(src_exports, {
45
+ var index_exports = {};
46
+ __export(index_exports, {
47
47
  viteAwesomeSvgLoader: () => viteAwesomeSvgLoader
48
48
  });
49
- module.exports = __toCommonJS(src_exports);
49
+ module.exports = __toCommonJS(index_exports);
50
50
  var import_fs_extra = __toESM(require("fs-extra"));
51
51
  var import_path = __toESM(require("path"));
52
52
  var import_svgo = require("svgo");
53
+ var import_xast = require("svgo/lib/xast.js");
53
54
  var csstree = __toESM(require("css-tree"));
54
55
  var import_imurmurhash = __toESM(require("imurmurhash"));
55
56
  var IMPORT_TYPES = ["url", "source", "source-data-uri", "base64", "base64-data-uri"];
56
57
  var DEFAULT_OPTIONS = {
57
58
  tempDir: ".temp",
58
59
  preserveLineWidthList: [],
60
+ skipPreserveLineWidthList: [],
61
+ skipPreserveLineWidthSelectors: [],
59
62
  setCurrentColorList: [],
63
+ skipSetCurrentColorList: [],
64
+ skipSetCurrentColorSelectors: [],
60
65
  skipTransformsList: [],
66
+ skipTransformsSelectors: [],
61
67
  skipFilesList: [],
62
68
  defaultImport: "source"
63
69
  };
@@ -136,18 +142,28 @@ function viteAwesomeSvgLoader(options = {}) {
136
142
  const query = {};
137
143
  for (const pair of queryKVPairs) {
138
144
  const [key, value] = pair.split("=");
139
- query[key.toLocaleLowerCase()] = value || "1";
145
+ query[key.toLowerCase()] = value || "1";
140
146
  }
141
- if (shouldDoThing(relPathWithSlash, query["skip-awesome-svg-loader"], mergedOptions.skipFilesList)) {
147
+ if (matchesQueryOrList(relPathWithSlash, query["skip-awesome-svg-loader"], mergedOptions.skipFilesList)) {
142
148
  return null;
143
149
  }
144
- const shouldSkipTransforms = shouldDoThing(
150
+ const shouldSkipTransforms = matchesQueryOrList(
145
151
  relPathWithSlash,
146
152
  query["skip-transforms"],
147
153
  mergedOptions.skipTransformsList
148
154
  );
149
- const shouldPreserveLineWidth = !shouldSkipTransforms && shouldDoThing(relPathWithSlash, query["preserve-line-width"], mergedOptions.preserveLineWidthList);
150
- const shouldSetCurrentColor = !shouldSkipTransforms && shouldDoThing(relPathWithSlash, query["set-current-color"], mergedOptions.setCurrentColorList);
155
+ const shouldPreserveLineWidth = !shouldSkipTransforms && matchesQueryOrList(relPathWithSlash, query["preserve-line-width"], mergedOptions.preserveLineWidthList) && !matchesQueryOrList(relPathWithSlash, void 0, mergedOptions.skipPreserveLineWidthList);
156
+ const shouldSetCurrentColor = !shouldSkipTransforms && matchesQueryOrList(relPathWithSlash, query["set-current-color"], mergedOptions.setCurrentColorList) && !matchesQueryOrList(relPathWithSlash, void 0, mergedOptions.skipSetCurrentColorList);
157
+ const skipPreserveLineWidthSelectors = selectorsToList(
158
+ relPathWithSlash,
159
+ mergedOptions.skipPreserveLineWidthSelectors
160
+ );
161
+ const skipSetCurrentColorSelectors = selectorsToList(
162
+ relPathWithSlash,
163
+ mergedOptions.skipSetCurrentColorSelectors
164
+ );
165
+ const skipTransformsSelectors = selectorsToList(relPathWithSlash, mergedOptions.skipTransformsSelectors);
166
+ const nodesWithOrigColors = [];
151
167
  let joinedParamsStr = "";
152
168
  for (const param of [shouldSkipTransforms, shouldPreserveLineWidth, shouldSetCurrentColor]) {
153
169
  joinedParamsStr += param ? "1" : "0";
@@ -174,13 +190,25 @@ function viteAwesomeSvgLoader(options = {}) {
174
190
  name: "awesome-svg-loader",
175
191
  fn: () => {
176
192
  return {
193
+ root: {
194
+ enter: (root2) => {
195
+ for (const selectors of [skipSetCurrentColorSelectors, skipTransformsSelectors]) {
196
+ for (const selector of selectors) {
197
+ nodesWithOrigColors.push(...(0, import_xast.querySelectorAll)(root2, selector));
198
+ }
199
+ }
200
+ }
201
+ },
177
202
  element: {
178
203
  enter: (node) => {
179
- if (shouldPreserveLineWidth) {
204
+ if (matchesSelectors(node, skipTransformsSelectors)) {
205
+ return;
206
+ }
207
+ if (shouldPreserveLineWidth && !matchesSelectors(node, skipPreserveLineWidthSelectors)) {
180
208
  preserveLineWidth(node, fullPath);
181
209
  }
182
- if (shouldSetCurrentColor) {
183
- isFillSetOnRoot = setCurrentColor(node, isFillSetOnRoot);
210
+ if (shouldSetCurrentColor && !matchesSelectors(node, skipSetCurrentColorSelectors)) {
211
+ isFillSetOnRoot = setCurrentColor(node, isFillSetOnRoot, nodesWithOrigColors);
184
212
  }
185
213
  }
186
214
  }
@@ -197,13 +225,13 @@ function viteAwesomeSvgLoader(options = {}) {
197
225
  }
198
226
  switch (importType) {
199
227
  case "source":
200
- return "export default `" + code.replaceAll("`", "\\`") + "`;";
228
+ return "export default `" + escapeBackticks(code) + "`;";
201
229
  case "source-data-uri":
202
- return "export default `data:image/svg+xml," + encodeURIComponent(code.replaceAll("`", "\\`")) + "`;";
230
+ return "export default `data:image/svg+xml," + encodeURIComponent(code) + "`;";
203
231
  case "base64":
204
- return "export default `" + toBase64(code).replaceAll("`", "\\`") + "`;";
232
+ return "export default `" + escapeBackticks(toBase64(code)) + "`;";
205
233
  case "base64-data-uri":
206
- return "export default `data:image/svg+xml;base64," + encodeURIComponent(toBase64(code)).replaceAll("`", "\\`") + "`;";
234
+ return "export default `data:image/svg+xml;base64," + encodeURIComponent(toBase64(code)) + "`;";
207
235
  }
208
236
  if (!isBuildMode) {
209
237
  const assetUrl = mergedOptions.tempDir + assetRelPath;
@@ -223,23 +251,51 @@ function toBase64(str) {
223
251
  const binString = String.fromCodePoint(...new TextEncoder().encode(str));
224
252
  return btoa(binString);
225
253
  }
226
- function shouldDoThing(relPathWithSlash, queryValue, list) {
227
- if ((queryValue == null ? void 0 : queryValue.toLocaleLowerCase()) === "false") {
254
+ function escapeBackticks(str) {
255
+ return str.replaceAll("`", "\\`");
256
+ }
257
+ function matchesQueryOrList(relPathWithSlash, queryValue, matchers) {
258
+ if ((queryValue == null ? void 0 : queryValue.toLowerCase()) === "false") {
228
259
  return false;
229
260
  }
230
261
  if (queryValue) {
231
262
  return true;
232
263
  }
264
+ return matchesPath(relPathWithSlash, matchers);
265
+ }
266
+ function matchesPath(relPathWithSlash, matchers) {
233
267
  const filename = import_path.default.basename(relPathWithSlash);
234
- for (const entry of list) {
235
- for (const name of [filename, relPathWithSlash]) {
236
- if (name === entry || entry instanceof RegExp && entry.exec(name)) {
268
+ const toMatch = [filename, relPathWithSlash];
269
+ for (const matcher of matchers) {
270
+ for (const entry of toMatch) {
271
+ if (entry === matcher || matcher instanceof RegExp && matcher.exec(entry)) {
237
272
  return true;
238
273
  }
239
274
  }
240
275
  }
241
276
  return false;
242
277
  }
278
+ function selectorsToList(relPathWithSlash, selectors) {
279
+ const resolvedSelectors = [];
280
+ for (const selector of selectors) {
281
+ if (typeof selector === "string") {
282
+ resolvedSelectors.push(selector);
283
+ continue;
284
+ }
285
+ if (matchesPath(relPathWithSlash, selector.files)) {
286
+ resolvedSelectors.push(...selector.selectors);
287
+ }
288
+ }
289
+ return resolvedSelectors;
290
+ }
291
+ function matchesSelectors(node, selectors) {
292
+ for (const selector of selectors) {
293
+ if ((0, import_xast.matches)(node, selector)) {
294
+ return true;
295
+ }
296
+ }
297
+ return false;
298
+ }
243
299
  var TAGS_TO_PRESERVE_LINE_WIDTH_OF = {
244
300
  circle: true,
245
301
  ellipse: true,
@@ -290,15 +346,15 @@ var IGNORE_COLORS = {
290
346
  transparent: true,
291
347
  currentColor: true
292
348
  };
293
- function setCurrentColor(node, isFillSetOnRoot) {
294
- var _a;
349
+ function setCurrentColor(node, isFillSetOnRoot, nodesWithOrigColors) {
295
350
  if (node.name === "style") {
296
- const newCss = setCurrentColorCss((_a = node.children[0]) == null ? void 0 : _a.value, false);
351
+ const firstChild = node.children[0];
352
+ const newCss = setCurrentColorCss(firstChild == null ? void 0 : firstChild.value, nodesWithOrigColors, false);
297
353
  if (newCss) {
298
- node.children[0].value = newCss;
354
+ firstChild.value = newCss;
299
355
  }
300
356
  } else {
301
- const newCss = setCurrentColorCss(node.attributes.style, true);
357
+ const newCss = setCurrentColorCss(node.attributes.style, nodesWithOrigColors, true);
302
358
  if (newCss) {
303
359
  node.attributes.style = newCss;
304
360
  }
@@ -319,7 +375,7 @@ function setCurrentColor(node, isFillSetOnRoot) {
319
375
  }
320
376
  return isFillSetOnRoot;
321
377
  }
322
- function setCurrentColorCss(css, isInline = false) {
378
+ function setCurrentColorCss(css, nodesWithOrigColors, isInline = false) {
323
379
  if (!css || typeof css !== "string") {
324
380
  return "";
325
381
  }
@@ -328,20 +384,70 @@ function setCurrentColorCss(css, isInline = false) {
328
384
  css = `{${css}}`;
329
385
  context = "block";
330
386
  }
387
+ const shouldPreserveColors = !isInline && nodesWithOrigColors.length;
388
+ let origColorSelectors = [];
389
+ let currentColorSelectors = [];
390
+ let didSplitSelectors = false;
331
391
  const ast = csstree.parse(css, { context });
332
- csstree.walk(ast, {
333
- visit: "Declaration",
334
- enter: (node) => {
335
- var _a, _b;
336
- if (!COLOR_ATTRS_TO_REPLACE[node.property]) {
392
+ csstree.walk(ast, function(node) {
393
+ var _a, _b, _c, _d, _e, _f, _g;
394
+ if (node.__SKIP_SVG_LOADER__ || ((_a = this.rule) == null ? void 0 : _a.__SKIP_SVG_LOADER__)) {
395
+ return;
396
+ }
397
+ if (shouldPreserveColors) {
398
+ if (node.type === "SelectorList") {
399
+ origColorSelectors = [];
400
+ currentColorSelectors = [];
401
+ didSplitSelectors = false;
337
402
  return;
338
403
  }
339
- const identifier = (_b = (_a = node.value) == null ? void 0 : _a.children) == null ? void 0 : _b.first;
340
- const color = (identifier == null ? void 0 : identifier.value) || (identifier == null ? void 0 : identifier.name);
341
- if (color && !IGNORE_COLORS[color]) {
342
- node.value = csstree.parse("currentColor", { context: "value" });
404
+ if (node.type === "Selector") {
405
+ const selector = csstree.generate(node);
406
+ let isOrigColor = false;
407
+ for (const svgNode of nodesWithOrigColors) {
408
+ if ((0, import_xast.matches)(svgNode, selector)) {
409
+ isOrigColor = true;
410
+ node.__ORIG_COLOR__ = true;
411
+ break;
412
+ }
413
+ }
414
+ (isOrigColor ? origColorSelectors : currentColorSelectors).push(selector);
415
+ return;
343
416
  }
344
417
  }
418
+ if (node.type !== "Declaration" || !COLOR_ATTRS_TO_REPLACE[node.property]) {
419
+ return;
420
+ }
421
+ const identifier = (_c = (_b = node.value) == null ? void 0 : _b.children) == null ? void 0 : _c.first;
422
+ const color = (identifier == null ? void 0 : identifier.value) || (identifier == null ? void 0 : identifier.name);
423
+ if (!color || IGNORE_COLORS[color]) {
424
+ return;
425
+ }
426
+ if (shouldPreserveColors && !didSplitSelectors && ((_d = this.rule) == null ? void 0 : _d.prelude.type) === "SelectorList") {
427
+ const origColorsRule = csstree.clone(this.rule);
428
+ origColorsRule.__SKIP_SVG_LOADER__ = true;
429
+ const origColorsSelectors = new csstree.List();
430
+ const selectors = this.rule.prelude.children;
431
+ selectors.forEach((node2, listItem) => {
432
+ if (node2.__ORIG_COLOR__) {
433
+ selectors.remove(listItem);
434
+ origColorsSelectors.push(node2);
435
+ }
436
+ });
437
+ origColorsRule.prelude.children = origColorsSelectors;
438
+ const parent = ((_f = (_e = this.atrule) == null ? void 0 : _e.block) == null ? void 0 : _f.children) || ((_g = this.stylesheet) == null ? void 0 : _g.children);
439
+ let insertBefore;
440
+ parent == null ? void 0 : parent.some((rule, listItem) => {
441
+ if (rule === this.rule) {
442
+ insertBefore = listItem;
443
+ return true;
444
+ }
445
+ return false;
446
+ });
447
+ insertBefore ? parent == null ? void 0 : parent.insertData(origColorsRule, insertBefore) : parent == null ? void 0 : parent.push(origColorsRule);
448
+ didSplitSelectors = true;
449
+ }
450
+ node.value = csstree.parse("currentColor", { context: "value" });
345
451
  });
346
452
  return csstree.generate(ast);
347
453
  }
package/index.mjs CHANGED
@@ -19,14 +19,20 @@ var __spreadValues = (a, b) => {
19
19
  import fs from "fs-extra";
20
20
  import path from "path";
21
21
  import { optimize } from "svgo";
22
+ import { matches as matchesSelector, querySelectorAll } from "svgo/lib/xast.js";
22
23
  import * as csstree from "css-tree";
23
24
  import MurmurHash3 from "imurmurhash";
24
25
  var IMPORT_TYPES = ["url", "source", "source-data-uri", "base64", "base64-data-uri"];
25
26
  var DEFAULT_OPTIONS = {
26
27
  tempDir: ".temp",
27
28
  preserveLineWidthList: [],
29
+ skipPreserveLineWidthList: [],
30
+ skipPreserveLineWidthSelectors: [],
28
31
  setCurrentColorList: [],
32
+ skipSetCurrentColorList: [],
33
+ skipSetCurrentColorSelectors: [],
29
34
  skipTransformsList: [],
35
+ skipTransformsSelectors: [],
30
36
  skipFilesList: [],
31
37
  defaultImport: "source"
32
38
  };
@@ -105,18 +111,28 @@ function viteAwesomeSvgLoader(options = {}) {
105
111
  const query = {};
106
112
  for (const pair of queryKVPairs) {
107
113
  const [key, value] = pair.split("=");
108
- query[key.toLocaleLowerCase()] = value || "1";
114
+ query[key.toLowerCase()] = value || "1";
109
115
  }
110
- if (shouldDoThing(relPathWithSlash, query["skip-awesome-svg-loader"], mergedOptions.skipFilesList)) {
116
+ if (matchesQueryOrList(relPathWithSlash, query["skip-awesome-svg-loader"], mergedOptions.skipFilesList)) {
111
117
  return null;
112
118
  }
113
- const shouldSkipTransforms = shouldDoThing(
119
+ const shouldSkipTransforms = matchesQueryOrList(
114
120
  relPathWithSlash,
115
121
  query["skip-transforms"],
116
122
  mergedOptions.skipTransformsList
117
123
  );
118
- const shouldPreserveLineWidth = !shouldSkipTransforms && shouldDoThing(relPathWithSlash, query["preserve-line-width"], mergedOptions.preserveLineWidthList);
119
- const shouldSetCurrentColor = !shouldSkipTransforms && shouldDoThing(relPathWithSlash, query["set-current-color"], mergedOptions.setCurrentColorList);
124
+ const shouldPreserveLineWidth = !shouldSkipTransforms && matchesQueryOrList(relPathWithSlash, query["preserve-line-width"], mergedOptions.preserveLineWidthList) && !matchesQueryOrList(relPathWithSlash, void 0, mergedOptions.skipPreserveLineWidthList);
125
+ const shouldSetCurrentColor = !shouldSkipTransforms && matchesQueryOrList(relPathWithSlash, query["set-current-color"], mergedOptions.setCurrentColorList) && !matchesQueryOrList(relPathWithSlash, void 0, mergedOptions.skipSetCurrentColorList);
126
+ const skipPreserveLineWidthSelectors = selectorsToList(
127
+ relPathWithSlash,
128
+ mergedOptions.skipPreserveLineWidthSelectors
129
+ );
130
+ const skipSetCurrentColorSelectors = selectorsToList(
131
+ relPathWithSlash,
132
+ mergedOptions.skipSetCurrentColorSelectors
133
+ );
134
+ const skipTransformsSelectors = selectorsToList(relPathWithSlash, mergedOptions.skipTransformsSelectors);
135
+ const nodesWithOrigColors = [];
120
136
  let joinedParamsStr = "";
121
137
  for (const param of [shouldSkipTransforms, shouldPreserveLineWidth, shouldSetCurrentColor]) {
122
138
  joinedParamsStr += param ? "1" : "0";
@@ -143,13 +159,25 @@ function viteAwesomeSvgLoader(options = {}) {
143
159
  name: "awesome-svg-loader",
144
160
  fn: () => {
145
161
  return {
162
+ root: {
163
+ enter: (root2) => {
164
+ for (const selectors of [skipSetCurrentColorSelectors, skipTransformsSelectors]) {
165
+ for (const selector of selectors) {
166
+ nodesWithOrigColors.push(...querySelectorAll(root2, selector));
167
+ }
168
+ }
169
+ }
170
+ },
146
171
  element: {
147
172
  enter: (node) => {
148
- if (shouldPreserveLineWidth) {
173
+ if (matchesSelectors(node, skipTransformsSelectors)) {
174
+ return;
175
+ }
176
+ if (shouldPreserveLineWidth && !matchesSelectors(node, skipPreserveLineWidthSelectors)) {
149
177
  preserveLineWidth(node, fullPath);
150
178
  }
151
- if (shouldSetCurrentColor) {
152
- isFillSetOnRoot = setCurrentColor(node, isFillSetOnRoot);
179
+ if (shouldSetCurrentColor && !matchesSelectors(node, skipSetCurrentColorSelectors)) {
180
+ isFillSetOnRoot = setCurrentColor(node, isFillSetOnRoot, nodesWithOrigColors);
153
181
  }
154
182
  }
155
183
  }
@@ -166,13 +194,13 @@ function viteAwesomeSvgLoader(options = {}) {
166
194
  }
167
195
  switch (importType) {
168
196
  case "source":
169
- return "export default `" + code.replaceAll("`", "\\`") + "`;";
197
+ return "export default `" + escapeBackticks(code) + "`;";
170
198
  case "source-data-uri":
171
- return "export default `data:image/svg+xml," + encodeURIComponent(code.replaceAll("`", "\\`")) + "`;";
199
+ return "export default `data:image/svg+xml," + encodeURIComponent(code) + "`;";
172
200
  case "base64":
173
- return "export default `" + toBase64(code).replaceAll("`", "\\`") + "`;";
201
+ return "export default `" + escapeBackticks(toBase64(code)) + "`;";
174
202
  case "base64-data-uri":
175
- return "export default `data:image/svg+xml;base64," + encodeURIComponent(toBase64(code)).replaceAll("`", "\\`") + "`;";
203
+ return "export default `data:image/svg+xml;base64," + encodeURIComponent(toBase64(code)) + "`;";
176
204
  }
177
205
  if (!isBuildMode) {
178
206
  const assetUrl = mergedOptions.tempDir + assetRelPath;
@@ -192,23 +220,51 @@ function toBase64(str) {
192
220
  const binString = String.fromCodePoint(...new TextEncoder().encode(str));
193
221
  return btoa(binString);
194
222
  }
195
- function shouldDoThing(relPathWithSlash, queryValue, list) {
196
- if ((queryValue == null ? void 0 : queryValue.toLocaleLowerCase()) === "false") {
223
+ function escapeBackticks(str) {
224
+ return str.replaceAll("`", "\\`");
225
+ }
226
+ function matchesQueryOrList(relPathWithSlash, queryValue, matchers) {
227
+ if ((queryValue == null ? void 0 : queryValue.toLowerCase()) === "false") {
197
228
  return false;
198
229
  }
199
230
  if (queryValue) {
200
231
  return true;
201
232
  }
233
+ return matchesPath(relPathWithSlash, matchers);
234
+ }
235
+ function matchesPath(relPathWithSlash, matchers) {
202
236
  const filename = path.basename(relPathWithSlash);
203
- for (const entry of list) {
204
- for (const name of [filename, relPathWithSlash]) {
205
- if (name === entry || entry instanceof RegExp && entry.exec(name)) {
237
+ const toMatch = [filename, relPathWithSlash];
238
+ for (const matcher of matchers) {
239
+ for (const entry of toMatch) {
240
+ if (entry === matcher || matcher instanceof RegExp && matcher.exec(entry)) {
206
241
  return true;
207
242
  }
208
243
  }
209
244
  }
210
245
  return false;
211
246
  }
247
+ function selectorsToList(relPathWithSlash, selectors) {
248
+ const resolvedSelectors = [];
249
+ for (const selector of selectors) {
250
+ if (typeof selector === "string") {
251
+ resolvedSelectors.push(selector);
252
+ continue;
253
+ }
254
+ if (matchesPath(relPathWithSlash, selector.files)) {
255
+ resolvedSelectors.push(...selector.selectors);
256
+ }
257
+ }
258
+ return resolvedSelectors;
259
+ }
260
+ function matchesSelectors(node, selectors) {
261
+ for (const selector of selectors) {
262
+ if (matchesSelector(node, selector)) {
263
+ return true;
264
+ }
265
+ }
266
+ return false;
267
+ }
212
268
  var TAGS_TO_PRESERVE_LINE_WIDTH_OF = {
213
269
  circle: true,
214
270
  ellipse: true,
@@ -259,15 +315,15 @@ var IGNORE_COLORS = {
259
315
  transparent: true,
260
316
  currentColor: true
261
317
  };
262
- function setCurrentColor(node, isFillSetOnRoot) {
263
- var _a;
318
+ function setCurrentColor(node, isFillSetOnRoot, nodesWithOrigColors) {
264
319
  if (node.name === "style") {
265
- const newCss = setCurrentColorCss((_a = node.children[0]) == null ? void 0 : _a.value, false);
320
+ const firstChild = node.children[0];
321
+ const newCss = setCurrentColorCss(firstChild == null ? void 0 : firstChild.value, nodesWithOrigColors, false);
266
322
  if (newCss) {
267
- node.children[0].value = newCss;
323
+ firstChild.value = newCss;
268
324
  }
269
325
  } else {
270
- const newCss = setCurrentColorCss(node.attributes.style, true);
326
+ const newCss = setCurrentColorCss(node.attributes.style, nodesWithOrigColors, true);
271
327
  if (newCss) {
272
328
  node.attributes.style = newCss;
273
329
  }
@@ -288,7 +344,7 @@ function setCurrentColor(node, isFillSetOnRoot) {
288
344
  }
289
345
  return isFillSetOnRoot;
290
346
  }
291
- function setCurrentColorCss(css, isInline = false) {
347
+ function setCurrentColorCss(css, nodesWithOrigColors, isInline = false) {
292
348
  if (!css || typeof css !== "string") {
293
349
  return "";
294
350
  }
@@ -297,20 +353,70 @@ function setCurrentColorCss(css, isInline = false) {
297
353
  css = `{${css}}`;
298
354
  context = "block";
299
355
  }
356
+ const shouldPreserveColors = !isInline && nodesWithOrigColors.length;
357
+ let origColorSelectors = [];
358
+ let currentColorSelectors = [];
359
+ let didSplitSelectors = false;
300
360
  const ast = csstree.parse(css, { context });
301
- csstree.walk(ast, {
302
- visit: "Declaration",
303
- enter: (node) => {
304
- var _a, _b;
305
- if (!COLOR_ATTRS_TO_REPLACE[node.property]) {
361
+ csstree.walk(ast, function(node) {
362
+ var _a, _b, _c, _d, _e, _f, _g;
363
+ if (node.__SKIP_SVG_LOADER__ || ((_a = this.rule) == null ? void 0 : _a.__SKIP_SVG_LOADER__)) {
364
+ return;
365
+ }
366
+ if (shouldPreserveColors) {
367
+ if (node.type === "SelectorList") {
368
+ origColorSelectors = [];
369
+ currentColorSelectors = [];
370
+ didSplitSelectors = false;
306
371
  return;
307
372
  }
308
- const identifier = (_b = (_a = node.value) == null ? void 0 : _a.children) == null ? void 0 : _b.first;
309
- const color = (identifier == null ? void 0 : identifier.value) || (identifier == null ? void 0 : identifier.name);
310
- if (color && !IGNORE_COLORS[color]) {
311
- node.value = csstree.parse("currentColor", { context: "value" });
373
+ if (node.type === "Selector") {
374
+ const selector = csstree.generate(node);
375
+ let isOrigColor = false;
376
+ for (const svgNode of nodesWithOrigColors) {
377
+ if (matchesSelector(svgNode, selector)) {
378
+ isOrigColor = true;
379
+ node.__ORIG_COLOR__ = true;
380
+ break;
381
+ }
382
+ }
383
+ (isOrigColor ? origColorSelectors : currentColorSelectors).push(selector);
384
+ return;
312
385
  }
313
386
  }
387
+ if (node.type !== "Declaration" || !COLOR_ATTRS_TO_REPLACE[node.property]) {
388
+ return;
389
+ }
390
+ const identifier = (_c = (_b = node.value) == null ? void 0 : _b.children) == null ? void 0 : _c.first;
391
+ const color = (identifier == null ? void 0 : identifier.value) || (identifier == null ? void 0 : identifier.name);
392
+ if (!color || IGNORE_COLORS[color]) {
393
+ return;
394
+ }
395
+ if (shouldPreserveColors && !didSplitSelectors && ((_d = this.rule) == null ? void 0 : _d.prelude.type) === "SelectorList") {
396
+ const origColorsRule = csstree.clone(this.rule);
397
+ origColorsRule.__SKIP_SVG_LOADER__ = true;
398
+ const origColorsSelectors = new csstree.List();
399
+ const selectors = this.rule.prelude.children;
400
+ selectors.forEach((node2, listItem) => {
401
+ if (node2.__ORIG_COLOR__) {
402
+ selectors.remove(listItem);
403
+ origColorsSelectors.push(node2);
404
+ }
405
+ });
406
+ origColorsRule.prelude.children = origColorsSelectors;
407
+ const parent = ((_f = (_e = this.atrule) == null ? void 0 : _e.block) == null ? void 0 : _f.children) || ((_g = this.stylesheet) == null ? void 0 : _g.children);
408
+ let insertBefore;
409
+ parent == null ? void 0 : parent.some((rule, listItem) => {
410
+ if (rule === this.rule) {
411
+ insertBefore = listItem;
412
+ return true;
413
+ }
414
+ return false;
415
+ });
416
+ insertBefore ? parent == null ? void 0 : parent.insertData(origColorsRule, insertBefore) : parent == null ? void 0 : parent.push(origColorsRule);
417
+ didSplitSelectors = true;
418
+ }
419
+ node.value = csstree.parse("currentColor", { context: "value" });
314
420
  });
315
421
  return csstree.generate(ast);
316
422
  }