@tomasvn/svgstore 3.1.2 → 3.1.3

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/CHANGELOG.md CHANGED
@@ -7,4 +7,8 @@
7
7
  - parsing of `linearGradient` elements
8
8
 
9
9
  # 3.1.2
10
- - update readme file
10
+ - update readme file
11
+
12
+ # 3.1.3
13
+ - add safe clean `def` util
14
+ - passing `opts`, `cleanDefs: true` would break `linearGradient`
@@ -3,7 +3,10 @@
3
3
  var svgstore = require('../../src/svgstore');
4
4
  var fs = require('fs');
5
5
 
6
- var sprites = svgstore({ fragmentIdentifier: (id) => `view-${id}` })
6
+ var sprites = svgstore({
7
+ fragmentIdentifier: (id) => `view-${id}`,
8
+ processGradient: true,
9
+ })
7
10
  .add('unicorn', fs.readFileSync('./assets/unicorn.svg', 'utf8'))
8
11
  .add('rainbow', fs.readFileSync('./assets/rainbow.svg', 'utf8'))
9
12
  .add('gradient', fs.readFileSync('./assets/gradient.svg', 'utf8'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomasvn/svgstore",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "Combines mulitple svg files into one.",
5
5
  "scripts": {
6
6
  "lint": "npx eslint --fix \"{src,test}/**/*.js\" && npx prettier --write \"{src,test}/**/*.js\"",
package/src/svgstore.js CHANGED
@@ -6,6 +6,7 @@ var removeAttributes = require('./utils/remove-attributes');
6
6
  var setAttributes = require('./utils/set-attributes');
7
7
  var svgToSymbol = require('./utils/svg-to-symbol');
8
8
  var getSvgRect = require('./utils/get-svg-rect');
9
+ var safeCleanDefs = require("./utils/safe-clean-defs");
9
10
 
10
11
  var SELECTOR_SVG = 'svg';
11
12
  var SELECTOR_DEFS = 'defs';
@@ -15,7 +16,19 @@ var TEMPLATE_DOCTYPE =
15
16
  '<?xml version="1.0" encoding="UTF-8"?>' +
16
17
  '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ' +
17
18
  '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
18
-
19
+ /**
20
+ * Default options used by svgstore.
21
+ * @typedef {Object} SvgstoreOptions
22
+ * @property {boolean} cleanDefs - Whether to clean <defs> elements.
23
+ * @property {boolean} cleanSymbols - Whether to clean <symbol> elements.
24
+ * @property {boolean} inline - Whether to output inline SVG.
25
+ * @property {boolean|Object} svgAttrs - Attributes to set on the root <svg>.
26
+ * @property {boolean|Object} symbolAttrs - Attributes to set on <symbol> elements.
27
+ * @property {boolean} copyAttrs - Whether to copy attributes from original SVG.
28
+ * @property {boolean} renameDefs - Whether to rename IDs inside <defs>.
29
+ * @property {function|null} fragmentIdentifier - Function to generate fragment identifiers.
30
+ * @property {boolean} processGradient - Whether to process gradients or not
31
+ */
19
32
  var DEFAULT_OPTIONS = {
20
33
  cleanDefs: false,
21
34
  cleanSymbols: false,
@@ -25,9 +38,17 @@ var DEFAULT_OPTIONS = {
25
38
  copyAttrs: false,
26
39
  renameDefs: false,
27
40
  fragmentIdentifier: null,
41
+ processGradient: false,
28
42
  };
29
43
 
44
+ /**
45
+ * Creates an SVG store to combine multiple SVG files into one.
46
+ *
47
+ * @param {Partial<SvgstoreOptions>} [options] - Configuration options to override defaults.
48
+ * @returns {Object} An object with methods to add SVGs and output the combined SVG.
49
+ */
30
50
  function svgstore(options) {
51
+ /** @type {SvgstoreOptions} */
31
52
  var svgstoreOptions = Object.assign({}, DEFAULT_OPTIONS, options);
32
53
 
33
54
  // <svg>
@@ -40,6 +61,14 @@ function svgstore(options) {
40
61
  return {
41
62
  element: parent,
42
63
 
64
+ /**
65
+ * Adds an SVG file to the store.
66
+ *
67
+ * @param {string} id - Unique identifier for the SVG symbol.
68
+ * @param {string} file - SVG file content or path to load.
69
+ * @param {Partial<SvgstoreOptions>} [options] - Options to override defaults for this addition.
70
+ * @returns {Object} The svgstore instance for chaining.
71
+ */
43
72
  add: function (id, file, options) {
44
73
  var child = loadXml(file);
45
74
  var addOptions = Object.assign({}, svgstoreOptions, options);
@@ -47,38 +76,56 @@ function svgstore(options) {
47
76
  // <defs>
48
77
  var childDefs = child(SELECTOR_DEFS);
49
78
 
50
- removeAttributes(childDefs, addOptions.cleanDefs);
51
-
52
- var linearGradients = childDefs.find('linearGradient');
53
- if (linearGradients.length) {
54
- linearGradients.each(function (i, elem) {
55
- var $elem = child(elem);
56
- var oldId = $elem.attr('id');
57
- if (!oldId) return;
58
-
59
- var newId = id + '__' + oldId;
60
- $elem.attr('id', newId);
61
-
62
- // Update references in fill, stroke, filter, style attributes
63
- child('[fill], [stroke], [filter], [style]').each(function (
64
- i,
65
- refElem
66
- ) {
67
- var $refElem = child(refElem);
68
- ['fill', 'stroke', 'filter', 'style'].forEach(function (
69
- attr
70
- ) {
71
- var val = $refElem.attr(attr);
72
- if (val && val.includes('url(#' + oldId + ')')) {
73
- var newVal = val.replace(
74
- new RegExp('url\\(#' + oldId + '\\)', 'g'),
75
- 'url(#' + newId + ')'
79
+ removeAttributes(childDefs, safeCleanDefs(addOptions.cleanDefs));
80
+
81
+ if (addOptions.processGradient) {
82
+ var linearGradients = childDefs.find('linearGradient');
83
+ if (linearGradients.length) {
84
+ linearGradients.each(function (i, elem) {
85
+ var $elem = child(elem);
86
+ var oldId = $elem.attr('id');
87
+ if (!oldId) return;
88
+
89
+ var newId = id + '__' + oldId;
90
+ $elem.attr('id', newId);
91
+
92
+ // Update references in fill, stroke, filter, style attributes
93
+ child('[fill], [stroke], [filter], [style]').each(
94
+ function (i, refElem) {
95
+ var $refElem = child(refElem);
96
+ ['fill', 'stroke', 'filter', 'style'].forEach(
97
+ function (attr) {
98
+ var val = $refElem.attr(attr);
99
+ if (
100
+ val &&
101
+ val.includes('url(#' + oldId + ')')
102
+ ) {
103
+ var newVal = val.replace(
104
+ new RegExp(
105
+ 'url\\(#' + oldId + '\\)',
106
+ 'g'
107
+ ),
108
+ 'url(#' + newId + ')'
109
+ );
110
+ $refElem.attr(attr, newVal);
111
+ }
112
+ }
76
113
  );
77
- $refElem.attr(attr, newVal);
78
114
  }
115
+ );
116
+
117
+ // Update <use> elements referencing the old gradient ID
118
+ child('use').each(function (i, useElem) {
119
+ var $useElem = child(useElem);
120
+ ['xlink:href', 'href'].forEach(function (prop) {
121
+ var val = $useElem.attr(prop);
122
+ if (val === '#' + oldId) {
123
+ $useElem.attr(prop, '#' + newId);
124
+ }
125
+ });
79
126
  });
80
127
  });
81
- });
128
+ }
82
129
  }
83
130
 
84
131
  /* rename defs ids (existing original logic) */
@@ -148,6 +195,12 @@ function svgstore(options) {
148
195
  return this;
149
196
  },
150
197
 
198
+ /**
199
+ * Converts the stored SVG elements to a string.
200
+ *
201
+ * @param {Partial<SvgstoreOptions>} [options] - Options to override defaults for output.
202
+ * @returns {string} The combined SVG as a string.
203
+ */
151
204
  toString: function (options) {
152
205
  // Create a clone so we don't modify the parent document.
153
206
  var clone = loadXml(parent.xml());
@@ -0,0 +1,11 @@
1
+ function safeCleanDefsAttrs(attrs) {
2
+ if (attrs === true) {
3
+ // Default to removing 'style' only outside of defs, but skip inside defs
4
+ return [];
5
+ }
6
+ if (!Array.isArray(attrs)) return [];
7
+ // Exclude 'style' to preserve gradient stops and fills
8
+ return attrs.filter((attr) => attr !== 'style' && attr !== 'id');
9
+ }
10
+
11
+ module.exports = safeCleanDefsAttrs;