@emasoft/svg-matrix 1.0.19 → 1.0.21

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.
@@ -0,0 +1,910 @@
1
+ /**
2
+ * SVG Collections - SVGO-compatible reference data
3
+ *
4
+ * This module provides comprehensive SVG element and attribute definitions,
5
+ * default values, and categorization data equivalent to SVGO's _collections.js
6
+ */
7
+
8
+ // ============================================================================
9
+ // INHERITABLE ATTRIBUTES
10
+ // ============================================================================
11
+
12
+ /**
13
+ * CSS properties that inherit from parent elements in SVG
14
+ * Reference: SVG 1.1 spec, CSS inheritance rules
15
+ */
16
+ export const inheritableAttrs = new Set([
17
+ 'clip-rule',
18
+ 'color',
19
+ 'color-interpolation',
20
+ 'color-interpolation-filters',
21
+ 'color-profile',
22
+ 'color-rendering',
23
+ 'cursor',
24
+ 'direction',
25
+ 'dominant-baseline',
26
+ 'fill',
27
+ 'fill-opacity',
28
+ 'fill-rule',
29
+ 'font',
30
+ 'font-family',
31
+ 'font-size',
32
+ 'font-size-adjust',
33
+ 'font-stretch',
34
+ 'font-style',
35
+ 'font-variant',
36
+ 'font-weight',
37
+ 'glyph-orientation-horizontal',
38
+ 'glyph-orientation-vertical',
39
+ 'image-rendering',
40
+ 'letter-spacing',
41
+ 'marker',
42
+ 'marker-end',
43
+ 'marker-mid',
44
+ 'marker-start',
45
+ 'paint-order',
46
+ 'pointer-events',
47
+ 'shape-rendering',
48
+ 'stroke',
49
+ 'stroke-dasharray',
50
+ 'stroke-dashoffset',
51
+ 'stroke-linecap',
52
+ 'stroke-linejoin',
53
+ 'stroke-miterlimit',
54
+ 'stroke-opacity',
55
+ 'stroke-width',
56
+ 'text-anchor',
57
+ 'text-rendering',
58
+ 'visibility',
59
+ 'word-spacing',
60
+ 'writing-mode',
61
+ ]);
62
+
63
+ /**
64
+ * Presentation attributes that do NOT inherit
65
+ */
66
+ export const nonInheritableAttrs = new Set([
67
+ 'clip-path',
68
+ 'display',
69
+ 'filter',
70
+ 'mask',
71
+ 'opacity',
72
+ 'text-decoration',
73
+ 'transform',
74
+ 'unicode-bidi',
75
+ ]);
76
+
77
+ // ============================================================================
78
+ // REFERENCE PROPERTIES
79
+ // ============================================================================
80
+
81
+ /**
82
+ * Attributes that can contain url() references to other elements
83
+ */
84
+ export const referencesProps = new Set([
85
+ 'clip-path',
86
+ 'color-profile',
87
+ 'fill',
88
+ 'filter',
89
+ 'href',
90
+ 'marker-end',
91
+ 'marker-mid',
92
+ 'marker-start',
93
+ 'mask',
94
+ 'stroke',
95
+ 'style',
96
+ 'xlink:href',
97
+ ]);
98
+
99
+ // ============================================================================
100
+ // ELEMENT GROUPS
101
+ // ============================================================================
102
+
103
+ export const elemsGroups = {
104
+ animation: new Set([
105
+ 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'set'
106
+ ]),
107
+ descriptive: new Set([
108
+ 'desc', 'metadata', 'title'
109
+ ]),
110
+ shape: new Set([
111
+ 'circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect'
112
+ ]),
113
+ structural: new Set([
114
+ 'defs', 'g', 'svg', 'symbol', 'use'
115
+ ]),
116
+ paintServer: new Set([
117
+ 'hatch', 'linearGradient', 'meshGradient', 'pattern', 'radialGradient', 'solidColor'
118
+ ]),
119
+ nonRendering: new Set([
120
+ 'clipPath', 'filter', 'linearGradient', 'marker', 'mask', 'pattern',
121
+ 'radialGradient', 'solidColor', 'symbol'
122
+ ]),
123
+ container: new Set([
124
+ 'a', 'defs', 'g', 'marker', 'mask', 'pattern', 'svg', 'switch', 'symbol'
125
+ ]),
126
+ textContent: new Set([
127
+ 'altGlyph', 'altGlyphDef', 'altGlyphItem', 'glyph', 'glyphRef',
128
+ 'text', 'textPath', 'tref', 'tspan'
129
+ ]),
130
+ filterPrimitive: new Set([
131
+ 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite',
132
+ 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap',
133
+ 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR',
134
+ 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology',
135
+ 'feOffset', 'feSpecularLighting', 'feTile', 'feTurbulence'
136
+ ]),
137
+ lightSource: new Set([
138
+ 'feDistantLight', 'fePointLight', 'feSpotLight'
139
+ ]),
140
+ };
141
+
142
+ // ============================================================================
143
+ // EDITOR NAMESPACES
144
+ // ============================================================================
145
+
146
+ /**
147
+ * Namespaces used by various SVG editors that can be safely removed
148
+ */
149
+ export const editorNamespaces = new Set([
150
+ 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
151
+ 'http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd',
152
+ 'http://www.inkscape.org/namespaces/inkscape',
153
+ 'http://www.bohemiancoding.com/sketch/ns',
154
+ 'http://ns.adobe.com/AdobeIllustrator/10.0/',
155
+ 'http://ns.adobe.com/Graphs/1.0/',
156
+ 'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/',
157
+ 'http://ns.adobe.com/Variables/1.0/',
158
+ 'http://ns.adobe.com/SaveForWeb/1.0/',
159
+ 'http://ns.adobe.com/Extensibility/1.0/',
160
+ 'http://ns.adobe.com/Flows/1.0/',
161
+ 'http://ns.adobe.com/ImageReplacement/1.0/',
162
+ 'http://ns.adobe.com/GenericCustomNamespace/1.0/',
163
+ 'http://ns.adobe.com/XPath/1.0/',
164
+ 'http://schemas.microsoft.com/visio/2003/SVGExtensions/',
165
+ 'http://taptrix.com/vectorillustrator/svg_extensions',
166
+ 'http://www.figma.com/figma/ns',
167
+ 'http://purl.org/dc/elements/1.1/',
168
+ 'http://creativecommons.org/ns#',
169
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
170
+ 'http://www.serif.com/',
171
+ 'http://www.vector.evaxdesign.sk',
172
+ ]);
173
+
174
+ // ============================================================================
175
+ // NAMED COLORS
176
+ // ============================================================================
177
+
178
+ /**
179
+ * SVG named colors to hex values
180
+ * Note: CSS color names are case-insensitive per spec.
181
+ * All keys are lowercase. When looking up colors, normalize input with .toLowerCase()
182
+ */
183
+ export const colorsNames = {
184
+ 'aliceblue': '#f0f8ff',
185
+ 'antiquewhite': '#faebd7',
186
+ 'aqua': '#0ff',
187
+ 'aquamarine': '#7fffd4',
188
+ 'azure': '#f0ffff',
189
+ 'beige': '#f5f5dc',
190
+ 'bisque': '#ffe4c4',
191
+ 'black': '#000',
192
+ 'blanchedalmond': '#ffebcd',
193
+ 'blue': '#00f',
194
+ 'blueviolet': '#8a2be2',
195
+ 'brown': '#a52a2a',
196
+ 'burlywood': '#deb887',
197
+ 'cadetblue': '#5f9ea0',
198
+ 'chartreuse': '#7fff00',
199
+ 'chocolate': '#d2691e',
200
+ 'coral': '#ff7f50',
201
+ 'cornflowerblue': '#6495ed',
202
+ 'cornsilk': '#fff8dc',
203
+ 'crimson': '#dc143c',
204
+ 'cyan': '#0ff',
205
+ 'darkblue': '#00008b',
206
+ 'darkcyan': '#008b8b',
207
+ 'darkgoldenrod': '#b8860b',
208
+ 'darkgray': '#a9a9a9',
209
+ 'darkgreen': '#006400',
210
+ 'darkgrey': '#a9a9a9',
211
+ 'darkkhaki': '#bdb76b',
212
+ 'darkmagenta': '#8b008b',
213
+ 'darkolivegreen': '#556b2f',
214
+ 'darkorange': '#ff8c00',
215
+ 'darkorchid': '#9932cc',
216
+ 'darkred': '#8b0000',
217
+ 'darksalmon': '#e9967a',
218
+ 'darkseagreen': '#8fbc8f',
219
+ 'darkslateblue': '#483d8b',
220
+ 'darkslategray': '#2f4f4f',
221
+ 'darkslategrey': '#2f4f4f',
222
+ 'darkturquoise': '#00ced1',
223
+ 'darkviolet': '#9400d3',
224
+ 'deeppink': '#ff1493',
225
+ 'deepskyblue': '#00bfff',
226
+ 'dimgray': '#696969',
227
+ 'dimgrey': '#696969',
228
+ 'dodgerblue': '#1e90ff',
229
+ 'firebrick': '#b22222',
230
+ 'floralwhite': '#fffaf0',
231
+ 'forestgreen': '#228b22',
232
+ 'fuchsia': '#f0f',
233
+ 'gainsboro': '#dcdcdc',
234
+ 'ghostwhite': '#f8f8ff',
235
+ 'gold': '#ffd700',
236
+ 'goldenrod': '#daa520',
237
+ 'gray': '#808080',
238
+ 'green': '#008000',
239
+ 'greenyellow': '#adff2f',
240
+ 'grey': '#808080',
241
+ 'honeydew': '#f0fff0',
242
+ 'hotpink': '#ff69b4',
243
+ 'indianred': '#cd5c5c',
244
+ 'indigo': '#4b0082',
245
+ 'ivory': '#fffff0',
246
+ 'khaki': '#f0e68c',
247
+ 'lavender': '#e6e6fa',
248
+ 'lavenderblush': '#fff0f5',
249
+ 'lawngreen': '#7cfc00',
250
+ 'lemonchiffon': '#fffacd',
251
+ 'lightblue': '#add8e6',
252
+ 'lightcoral': '#f08080',
253
+ 'lightcyan': '#e0ffff',
254
+ 'lightgoldenrodyellow': '#fafad2',
255
+ 'lightgray': '#d3d3d3',
256
+ 'lightgreen': '#90ee90',
257
+ 'lightgrey': '#d3d3d3',
258
+ 'lightpink': '#ffb6c1',
259
+ 'lightsalmon': '#ffa07a',
260
+ 'lightseagreen': '#20b2aa',
261
+ 'lightskyblue': '#87cefa',
262
+ 'lightslategray': '#789',
263
+ 'lightslategrey': '#789',
264
+ 'lightsteelblue': '#b0c4de',
265
+ 'lightyellow': '#ffffe0',
266
+ 'lime': '#0f0',
267
+ 'limegreen': '#32cd32',
268
+ 'linen': '#faf0e6',
269
+ 'magenta': '#f0f',
270
+ 'maroon': '#800000',
271
+ 'mediumaquamarine': '#66cdaa',
272
+ 'mediumblue': '#0000cd',
273
+ 'mediumorchid': '#ba55d3',
274
+ 'mediumpurple': '#9370db',
275
+ 'mediumseagreen': '#3cb371',
276
+ 'mediumslateblue': '#7b68ee',
277
+ 'mediumspringgreen': '#00fa9a',
278
+ 'mediumturquoise': '#48d1cc',
279
+ 'mediumvioletred': '#c71585',
280
+ 'midnightblue': '#191970',
281
+ 'mintcream': '#f5fffa',
282
+ 'mistyrose': '#ffe4e1',
283
+ 'moccasin': '#ffe4b5',
284
+ 'navajowhite': '#ffdead',
285
+ 'navy': '#000080',
286
+ 'oldlace': '#fdf5e6',
287
+ 'olive': '#808000',
288
+ 'olivedrab': '#6b8e23',
289
+ 'orange': '#ffa500',
290
+ 'orangered': '#ff4500',
291
+ 'orchid': '#da70d6',
292
+ 'palegoldenrod': '#eee8aa',
293
+ 'palegreen': '#98fb98',
294
+ 'paleturquoise': '#afeeee',
295
+ 'palevioletred': '#db7093',
296
+ 'papayawhip': '#ffefd5',
297
+ 'peachpuff': '#ffdab9',
298
+ 'peru': '#cd853f',
299
+ 'pink': '#ffc0cb',
300
+ 'plum': '#dda0dd',
301
+ 'powderblue': '#b0e0e6',
302
+ 'purple': '#800080',
303
+ 'rebeccapurple': '#639',
304
+ 'red': '#f00',
305
+ 'rosybrown': '#bc8f8f',
306
+ 'royalblue': '#4169e1',
307
+ 'saddlebrown': '#8b4513',
308
+ 'salmon': '#fa8072',
309
+ 'sandybrown': '#f4a460',
310
+ 'seagreen': '#2e8b57',
311
+ 'seashell': '#fff5ee',
312
+ 'sienna': '#a0522d',
313
+ 'silver': '#c0c0c0',
314
+ 'skyblue': '#87ceeb',
315
+ 'slateblue': '#6a5acd',
316
+ 'slategray': '#708090',
317
+ 'slategrey': '#708090',
318
+ 'snow': '#fffafa',
319
+ 'springgreen': '#00ff7f',
320
+ 'steelblue': '#4682b4',
321
+ 'tan': '#d2b48c',
322
+ 'teal': '#008080',
323
+ 'thistle': '#d8bfd8',
324
+ 'tomato': '#ff6347',
325
+ 'turquoise': '#40e0d0',
326
+ 'violet': '#ee82ee',
327
+ 'wheat': '#f5deb3',
328
+ 'white': '#fff',
329
+ 'whitesmoke': '#f5f5f5',
330
+ 'yellow': '#ff0',
331
+ 'yellowgreen': '#9acd32',
332
+ };
333
+
334
+ /**
335
+ * Hex values that have shorter color names
336
+ */
337
+ export const colorsShortNames = {
338
+ '#f0ffff': 'azure',
339
+ '#f5f5dc': 'beige',
340
+ '#ffe4c4': 'bisque',
341
+ '#a52a2a': 'brown',
342
+ '#ff7f50': 'coral',
343
+ '#ffd700': 'gold',
344
+ '#808080': 'gray',
345
+ '#008000': 'green',
346
+ '#4b0082': 'indigo',
347
+ '#fffff0': 'ivory',
348
+ '#f0e68c': 'khaki',
349
+ '#faf0e6': 'linen',
350
+ '#800000': 'maroon',
351
+ '#000080': 'navy',
352
+ '#808000': 'olive',
353
+ '#ffa500': 'orange',
354
+ '#da70d6': 'orchid',
355
+ '#cd853f': 'peru',
356
+ '#ffc0cb': 'pink',
357
+ '#dda0dd': 'plum',
358
+ '#800080': 'purple',
359
+ '#f00': 'red',
360
+ '#fa8072': 'salmon',
361
+ '#a0522d': 'sienna',
362
+ '#c0c0c0': 'silver',
363
+ '#fffafa': 'snow',
364
+ '#d2b48c': 'tan',
365
+ '#008080': 'teal',
366
+ '#ff6347': 'tomato',
367
+ '#ee82ee': 'violet',
368
+ '#f5deb3': 'wheat',
369
+ '#fff': 'white',
370
+ '#ff0': 'yellow',
371
+ };
372
+
373
+ // ============================================================================
374
+ // COLOR PROPERTIES
375
+ // ============================================================================
376
+
377
+ /**
378
+ * Attributes that accept color values
379
+ */
380
+ export const colorsProps = new Set([
381
+ 'color',
382
+ 'fill',
383
+ 'flood-color',
384
+ 'lighting-color',
385
+ 'stop-color',
386
+ 'stroke',
387
+ ]);
388
+
389
+ // ============================================================================
390
+ // ALL SVG ELEMENTS
391
+ // ============================================================================
392
+
393
+ /**
394
+ * Complete list of known SVG elements
395
+ */
396
+ export const knownElements = new Set([
397
+ // Structural elements
398
+ 'svg', 'g', 'defs', 'symbol', 'use',
399
+ // Shape elements
400
+ 'path', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon',
401
+ // Text elements
402
+ 'text', 'tspan', 'tref', 'textPath', 'altGlyph', 'altGlyphDef',
403
+ 'altGlyphItem', 'glyph', 'glyphRef',
404
+ // Gradient elements
405
+ 'linearGradient', 'radialGradient', 'meshGradient', 'stop',
406
+ // Container elements
407
+ 'a', 'marker', 'mask', 'pattern', 'clipPath', 'switch',
408
+ // Filter elements
409
+ 'filter', 'feBlend', 'feColorMatrix', 'feComponentTransfer',
410
+ 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting',
411
+ 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood',
412
+ 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur',
413
+ 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset',
414
+ 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile',
415
+ 'feTurbulence',
416
+ // Descriptive elements
417
+ 'title', 'desc', 'metadata',
418
+ // Animation elements
419
+ 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'set', 'mpath',
420
+ // Other elements
421
+ 'image', 'foreignObject', 'view', 'style', 'script',
422
+ 'solidColor', 'hatch', 'hatchpath',
423
+ ]);
424
+
425
+ // ============================================================================
426
+ // DEFAULT VALUES
427
+ // ============================================================================
428
+
429
+ /**
430
+ * General presentation attribute default values
431
+ */
432
+ export const presentationDefaults = {
433
+ // Fill defaults
434
+ 'fill': '#000',
435
+ 'fill-opacity': '1',
436
+ 'fill-rule': 'nonzero',
437
+
438
+ // Stroke defaults
439
+ 'stroke': 'none',
440
+ 'stroke-width': '1',
441
+ 'stroke-opacity': '1',
442
+ 'stroke-linecap': 'butt',
443
+ 'stroke-linejoin': 'miter',
444
+ 'stroke-miterlimit': '4',
445
+ 'stroke-dasharray': 'none',
446
+ 'stroke-dashoffset': '0',
447
+
448
+ // Opacity/visibility defaults
449
+ 'opacity': '1',
450
+ 'visibility': 'visible',
451
+ 'display': 'inline',
452
+
453
+ // Clip/mask defaults
454
+ 'clip': 'auto',
455
+ 'clip-path': 'none',
456
+ 'clip-rule': 'nonzero',
457
+ 'mask': 'none',
458
+
459
+ // Marker defaults
460
+ 'marker-start': 'none',
461
+ 'marker-mid': 'none',
462
+ 'marker-end': 'none',
463
+
464
+ // Color defaults
465
+ 'stop-color': '#000',
466
+ 'stop-opacity': '1',
467
+ 'flood-color': '#000',
468
+ 'flood-opacity': '1',
469
+ 'lighting-color': '#fff',
470
+
471
+ // Rendering defaults
472
+ 'color-interpolation': 'sRGB',
473
+ 'color-interpolation-filters': 'linearRGB',
474
+ 'color-rendering': 'auto',
475
+ 'shape-rendering': 'auto',
476
+ 'text-rendering': 'auto',
477
+ 'image-rendering': 'auto',
478
+
479
+ // Paint defaults
480
+ 'paint-order': 'normal',
481
+ 'vector-effect': 'none',
482
+
483
+ // Text defaults
484
+ 'text-anchor': 'start',
485
+ 'text-overflow': 'clip',
486
+ 'text-decoration': 'none',
487
+ 'dominant-baseline': 'auto',
488
+ 'alignment-baseline': 'baseline',
489
+ 'baseline-shift': 'baseline',
490
+ 'writing-mode': 'lr-tb',
491
+ 'direction': 'ltr',
492
+ 'unicode-bidi': 'normal',
493
+ 'letter-spacing': 'normal',
494
+ 'word-spacing': 'normal',
495
+
496
+ // Font defaults
497
+ 'font-style': 'normal',
498
+ 'font-variant': 'normal',
499
+ 'font-weight': 'normal',
500
+ 'font-stretch': 'normal',
501
+ 'font-size': 'medium',
502
+ 'font-size-adjust': 'none',
503
+
504
+ // Deprecated but still present
505
+ 'glyph-orientation-vertical': 'auto',
506
+ 'glyph-orientation-horizontal': '0deg',
507
+ };
508
+
509
+ /**
510
+ * Element-specific default values
511
+ */
512
+ export const elementDefaults = {
513
+ 'circle': { 'cx': '0', 'cy': '0' },
514
+ 'ellipse': { 'cx': '0', 'cy': '0' },
515
+ 'line': { 'x1': '0', 'y1': '0', 'x2': '0', 'y2': '0' },
516
+ 'rect': { 'x': '0', 'y': '0', 'rx': '0', 'ry': '0' },
517
+ 'image': { 'x': '0', 'y': '0', 'preserveAspectRatio': 'xMidYMid meet' },
518
+ 'svg': { 'x': '0', 'y': '0', 'preserveAspectRatio': 'xMidYMid meet' },
519
+ 'symbol': { 'preserveAspectRatio': 'xMidYMid meet' },
520
+ 'marker': {
521
+ 'markerUnits': 'strokeWidth',
522
+ 'refX': '0', 'refY': '0',
523
+ 'markerWidth': '3', 'markerHeight': '3'
524
+ },
525
+ 'linearGradient': {
526
+ 'x1': '0', 'y1': '0', 'x2': '100%', 'y2': '0',
527
+ 'spreadMethod': 'pad'
528
+ },
529
+ 'radialGradient': {
530
+ 'cx': '50%', 'cy': '50%', 'r': '50%',
531
+ // Note: fx and fy default to cx and cy values respectively per SVG spec,
532
+ // but this cannot be expressed in static defaults. Omitted to avoid incorrect values.
533
+ 'spreadMethod': 'pad'
534
+ },
535
+ 'pattern': {
536
+ 'x': '0', 'y': '0',
537
+ 'patternUnits': 'objectBoundingBox',
538
+ 'patternContentUnits': 'userSpaceOnUse'
539
+ },
540
+ 'clipPath': { 'clipPathUnits': 'userSpaceOnUse' },
541
+ 'mask': {
542
+ 'maskUnits': 'objectBoundingBox',
543
+ 'maskContentUnits': 'userSpaceOnUse',
544
+ 'x': '-10%', 'y': '-10%', 'width': '120%', 'height': '120%'
545
+ },
546
+ 'filter': {
547
+ 'primitiveUnits': 'objectBoundingBox',
548
+ 'x': '-10%', 'y': '-10%', 'width': '120%', 'height': '120%'
549
+ },
550
+ 'feBlend': { 'mode': 'normal' },
551
+ 'feColorMatrix': { 'type': 'matrix' },
552
+ 'feComposite': { 'operator': 'over', 'k1': '0', 'k2': '0', 'k3': '0', 'k4': '0' },
553
+ 'feConvolveMatrix': { 'order': '3', 'bias': '0', 'edgeMode': 'duplicate', 'preserveAlpha': 'false' },
554
+ 'feDisplacementMap': { 'scale': '0', 'xChannelSelector': 'A', 'yChannelSelector': 'A' },
555
+ 'feDistantLight': { 'azimuth': '0', 'elevation': '0' },
556
+ 'fePointLight': { 'x': '0', 'y': '0', 'z': '0' },
557
+ 'feSpotLight': {
558
+ 'x': '0', 'y': '0', 'z': '0',
559
+ 'pointsAtX': '0', 'pointsAtY': '0', 'pointsAtZ': '0',
560
+ 'specularExponent': '1'
561
+ },
562
+ 'feTurbulence': {
563
+ 'baseFrequency': '0', 'numOctaves': '1', 'seed': '0',
564
+ 'stitchTiles': 'noStitch', 'type': 'turbulence'
565
+ },
566
+ 'feFuncR': { 'type': 'identity', 'slope': '1', 'intercept': '0', 'amplitude': '1', 'exponent': '1', 'offset': '0' },
567
+ 'feFuncG': { 'type': 'identity', 'slope': '1', 'intercept': '0', 'amplitude': '1', 'exponent': '1', 'offset': '0' },
568
+ 'feFuncB': { 'type': 'identity', 'slope': '1', 'intercept': '0', 'amplitude': '1', 'exponent': '1', 'offset': '0' },
569
+ 'feFuncA': { 'type': 'identity', 'slope': '1', 'intercept': '0', 'amplitude': '1', 'exponent': '1', 'offset': '0' },
570
+ 'a': { 'target': '_self' },
571
+ 'textPath': { 'startOffset': '0' },
572
+ 'animate': { 'begin': '0s' },
573
+ 'animateMotion': { 'rotate': '0' },
574
+ };
575
+
576
+ // ============================================================================
577
+ // ELEMENT-SPECIFIC SETS (P4 Edge Cases)
578
+ // ============================================================================
579
+
580
+ /**
581
+ * Text-related elements that can contain text content
582
+ */
583
+ export const textElems = new Set([
584
+ 'altGlyph', 'textPath', 'tref', 'tspan', 'text', 'title', 'desc'
585
+ ]);
586
+
587
+ /**
588
+ * Elements that can contain path data
589
+ */
590
+ export const pathElems = new Set([
591
+ 'glyph', 'missing-glyph', 'path'
592
+ ]);
593
+
594
+ // ============================================================================
595
+ // ATTRIBUTE GROUPS (P4-4: 15 SVGO-compatible attribute groups)
596
+ // ============================================================================
597
+
598
+ /**
599
+ * Complete attribute groups matching SVGO's _collections.js
600
+ */
601
+ export const attrsGroups = {
602
+ animationAddition: new Set([
603
+ 'additive', 'accumulate'
604
+ ]),
605
+ animationAttributeTarget: new Set([
606
+ 'attributeType', 'attributeName'
607
+ ]),
608
+ animationEvent: new Set([
609
+ 'onbegin', 'onend', 'onrepeat', 'onload'
610
+ ]),
611
+ animationTiming: new Set([
612
+ 'begin', 'dur', 'end', 'min', 'max', 'restart', 'repeatCount', 'repeatDur', 'fill'
613
+ ]),
614
+ animationValue: new Set([
615
+ 'calcMode', 'values', 'keyTimes', 'keySplines', 'from', 'to', 'by'
616
+ ]),
617
+ conditionalProcessing: new Set([
618
+ 'requiredFeatures', 'requiredExtensions', 'systemLanguage'
619
+ ]),
620
+ core: new Set([
621
+ 'id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space', 'lang'
622
+ ]),
623
+ graphicalEvent: new Set([
624
+ 'onfocusin', 'onfocusout', 'onactivate', 'onclick', 'onmousedown',
625
+ 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onload'
626
+ ]),
627
+ presentation: new Set([
628
+ 'alignment-baseline', 'baseline-shift', 'clip', 'clip-path', 'clip-rule',
629
+ 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile',
630
+ 'color-rendering', 'cursor', 'direction', 'display', 'dominant-baseline',
631
+ 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter',
632
+ 'flood-color', 'flood-opacity', 'font', 'font-family', 'font-size',
633
+ 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight',
634
+ 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'image-rendering',
635
+ 'kerning', 'letter-spacing', 'lighting-color', 'marker', 'marker-end',
636
+ 'marker-mid', 'marker-start', 'mask', 'opacity', 'overflow', 'paint-order',
637
+ 'pointer-events', 'shape-rendering', 'stop-color', 'stop-opacity', 'stroke',
638
+ 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin',
639
+ 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor',
640
+ 'text-decoration', 'text-rendering', 'transform', 'transform-origin',
641
+ 'unicode-bidi', 'vector-effect', 'visibility', 'word-spacing', 'writing-mode'
642
+ ]),
643
+ xlink: new Set([
644
+ 'xlink:href', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role',
645
+ 'xlink:arcrole', 'xlink:title'
646
+ ]),
647
+ documentEvent: new Set([
648
+ 'onunload', 'onabort', 'onerror', 'onresize', 'onscroll', 'onzoom'
649
+ ]),
650
+ documentElementEvent: new Set([
651
+ 'oncopy', 'oncut', 'onpaste'
652
+ ]),
653
+ globalEvent: new Set([
654
+ 'oncancel', 'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', 'onclose',
655
+ 'oncuechange', 'ondblclick', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave',
656
+ 'ondragover', 'ondragstart', 'ondrop', 'ondurationchange', 'onemptied', 'onended',
657
+ 'onerror', 'onfocus', 'oninput', 'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup',
658
+ 'onload', 'onloadeddata', 'onloadedmetadata', 'onloadstart', 'onmousedown',
659
+ 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover',
660
+ 'onmouseup', 'onmousewheel', 'onpause', 'onplay', 'onplaying', 'onprogress',
661
+ 'onratechange', 'onreset', 'onresize', 'onscroll', 'onseeked', 'onseeking',
662
+ 'onselect', 'onshow', 'onstalled', 'onsubmit', 'onsuspend', 'ontimeupdate',
663
+ 'ontoggle', 'onvolumechange', 'onwaiting'
664
+ ]),
665
+ filterPrimitive: new Set([
666
+ 'x', 'y', 'width', 'height', 'result'
667
+ ]),
668
+ transferFunction: new Set([
669
+ 'type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset'
670
+ ]),
671
+ };
672
+
673
+ // ============================================================================
674
+ // DEPRECATED ATTRIBUTES (P4-5)
675
+ // ============================================================================
676
+
677
+ /**
678
+ * Deprecated attributes per group - used for warnings or removal
679
+ */
680
+ export const attrsGroupsDeprecated = {
681
+ presentation: new Set([
682
+ 'enable-background', 'glyph-orientation-horizontal', 'glyph-orientation-vertical',
683
+ 'kerning', 'clip'
684
+ ]),
685
+ xlink: new Set([
686
+ 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title', 'xlink:show', 'xlink:actuate'
687
+ ]),
688
+ core: new Set([
689
+ 'xml:base', 'xml:lang', 'xml:space'
690
+ ]),
691
+ };
692
+
693
+ // ============================================================================
694
+ // PARENT-CHILD VALIDATION (P4-1: allowedChildrenPerElement)
695
+ // ============================================================================
696
+
697
+ /**
698
+ * Defines which child elements are allowed for each SVG element
699
+ * Used for validation and removing invalid children
700
+ */
701
+ export const allowedChildrenPerElement = {
702
+ 'svg': new Set([
703
+ 'a', 'altGlyphDef', 'animate', 'animateColor', 'animateMotion', 'animateTransform',
704
+ 'circle', 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face',
705
+ 'foreignObject', 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata',
706
+ 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script',
707
+ 'set', 'style', 'svg', 'switch', 'symbol', 'text', 'title', 'use', 'view'
708
+ ]),
709
+ 'g': new Set([
710
+ 'a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle',
711
+ 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face', 'foreignObject',
712
+ 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'path',
713
+ 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script', 'set', 'style',
714
+ 'svg', 'switch', 'symbol', 'text', 'title', 'use'
715
+ ]),
716
+ 'defs': new Set([
717
+ 'a', 'altGlyphDef', 'animate', 'animateColor', 'animateMotion', 'animateTransform',
718
+ 'circle', 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face',
719
+ 'foreignObject', 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata',
720
+ 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script',
721
+ 'set', 'style', 'svg', 'switch', 'symbol', 'text', 'title', 'use', 'view'
722
+ ]),
723
+ 'symbol': new Set([
724
+ 'a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle',
725
+ 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face', 'foreignObject',
726
+ 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'path',
727
+ 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script', 'set', 'style',
728
+ 'svg', 'switch', 'symbol', 'text', 'title', 'use'
729
+ ]),
730
+ 'marker': new Set([
731
+ 'a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle',
732
+ 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face', 'foreignObject',
733
+ 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'path',
734
+ 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script', 'set', 'style',
735
+ 'svg', 'switch', 'symbol', 'text', 'title', 'use'
736
+ ]),
737
+ 'clipPath': new Set([
738
+ 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle', 'desc',
739
+ 'ellipse', 'line', 'metadata', 'path', 'polygon', 'polyline', 'rect', 'set', 'text',
740
+ 'title', 'use'
741
+ ]),
742
+ 'mask': new Set([
743
+ 'a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle',
744
+ 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face', 'foreignObject',
745
+ 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'path',
746
+ 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script', 'set', 'style',
747
+ 'svg', 'switch', 'symbol', 'text', 'title', 'use'
748
+ ]),
749
+ 'pattern': new Set([
750
+ 'a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle',
751
+ 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face', 'foreignObject',
752
+ 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'path',
753
+ 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script', 'set', 'style',
754
+ 'svg', 'switch', 'symbol', 'text', 'title', 'use'
755
+ ]),
756
+ 'a': new Set([
757
+ 'a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle',
758
+ 'clipPath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'font-face', 'foreignObject',
759
+ 'g', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'path',
760
+ 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'script', 'set', 'style',
761
+ 'svg', 'switch', 'symbol', 'text', 'title', 'use', 'view'
762
+ ]),
763
+ 'switch': new Set([
764
+ 'a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle',
765
+ 'desc', 'ellipse', 'foreignObject', 'g', 'image', 'line', 'metadata', 'path',
766
+ 'polygon', 'polyline', 'rect', 'set', 'svg', 'switch', 'text', 'title', 'use'
767
+ ]),
768
+ 'text': new Set([
769
+ 'a', 'altGlyph', 'animate', 'animateColor', 'animateMotion', 'animateTransform',
770
+ 'desc', 'metadata', 'set', 'textPath', 'title', 'tref', 'tspan'
771
+ ]),
772
+ 'textPath': new Set([
773
+ 'a', 'altGlyph', 'animate', 'animateColor', 'desc', 'metadata', 'set', 'title', 'tref', 'tspan'
774
+ ]),
775
+ 'tspan': new Set([
776
+ 'a', 'altGlyph', 'animate', 'animateColor', 'desc', 'metadata', 'set', 'title', 'tref', 'tspan'
777
+ ]),
778
+ 'linearGradient': new Set([
779
+ 'animate', 'animateTransform', 'desc', 'metadata', 'set', 'stop', 'title'
780
+ ]),
781
+ 'radialGradient': new Set([
782
+ 'animate', 'animateTransform', 'desc', 'metadata', 'set', 'stop', 'title'
783
+ ]),
784
+ 'filter': new Set([
785
+ 'animate', 'animateTransform', 'desc', 'feBlend', 'feColorMatrix', 'feComponentTransfer',
786
+ 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap',
787
+ 'feDropShadow', 'feFlood', 'feGaussianBlur', 'feImage', 'feMerge', 'feMorphology',
788
+ 'feOffset', 'feSpecularLighting', 'feTile', 'feTurbulence', 'metadata', 'set', 'title'
789
+ ]),
790
+ 'feBlend': new Set(['animate', 'set']),
791
+ 'feColorMatrix': new Set(['animate', 'set']),
792
+ 'feComponentTransfer': new Set(['feFuncA', 'feFuncB', 'feFuncG', 'feFuncR']),
793
+ 'feComposite': new Set(['animate', 'set']),
794
+ 'feConvolveMatrix': new Set(['animate', 'set']),
795
+ 'feDiffuseLighting': new Set(['animate', 'feDistantLight', 'fePointLight', 'feSpotLight', 'set']),
796
+ 'feDisplacementMap': new Set(['animate', 'set']),
797
+ 'feDropShadow': new Set(['animate', 'set']),
798
+ 'feFlood': new Set(['animate', 'set']),
799
+ 'feFuncA': new Set(['animate', 'set']),
800
+ 'feFuncB': new Set(['animate', 'set']),
801
+ 'feFuncG': new Set(['animate', 'set']),
802
+ 'feFuncR': new Set(['animate', 'set']),
803
+ 'feGaussianBlur': new Set(['animate', 'set']),
804
+ 'feImage': new Set(['animate', 'set']),
805
+ 'feMerge': new Set(['feMergeNode']),
806
+ 'feMergeNode': new Set(['animate', 'set']),
807
+ 'feMorphology': new Set(['animate', 'set']),
808
+ 'feOffset': new Set(['animate', 'set']),
809
+ 'feSpecularLighting': new Set(['animate', 'feDistantLight', 'fePointLight', 'feSpotLight', 'set']),
810
+ 'feTile': new Set(['animate', 'set']),
811
+ 'feTurbulence': new Set(['animate', 'set']),
812
+ 'animate': new Set(['desc', 'metadata', 'title']),
813
+ 'animateColor': new Set(['desc', 'metadata', 'title']),
814
+ 'animateMotion': new Set(['desc', 'metadata', 'mpath', 'title']),
815
+ 'animateTransform': new Set(['desc', 'metadata', 'title']),
816
+ 'set': new Set(['desc', 'metadata', 'title']),
817
+ // Shape elements cannot have children (except animation)
818
+ 'circle': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
819
+ 'ellipse': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
820
+ 'line': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
821
+ 'path': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
822
+ 'polygon': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
823
+ 'polyline': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
824
+ 'rect': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
825
+ 'image': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
826
+ 'use': new Set(['animate', 'animateColor', 'animateMotion', 'animateTransform', 'desc', 'metadata', 'set', 'title']),
827
+ // Descriptive elements have no children
828
+ 'title': new Set([]),
829
+ 'desc': new Set([]),
830
+ 'metadata': new Set([]), // Can have any XML content, but SVG-wise empty
831
+ // Light source elements
832
+ 'feDistantLight': new Set(['animate', 'set']),
833
+ 'fePointLight': new Set(['animate', 'set']),
834
+ 'feSpotLight': new Set(['animate', 'set']),
835
+ // Stop element
836
+ 'stop': new Set(['animate', 'set']),
837
+ // Other elements
838
+ 'foreignObject': new Set([]), // Can contain any non-SVG content
839
+ 'style': new Set([]),
840
+ 'script': new Set([]),
841
+ 'view': new Set(['desc', 'metadata', 'title']),
842
+ 'mpath': new Set(['desc', 'metadata', 'title']),
843
+ };
844
+
845
+ // ============================================================================
846
+ // CSS PSEUDO-CLASSES (P4 Edge Case: inlineStyles support)
847
+ // ============================================================================
848
+
849
+ /**
850
+ * CSS pseudo-classes that cannot be evaluated server-side
851
+ * (must be preserved in stylesheets)
852
+ */
853
+ export const pseudoClasses = {
854
+ // User action pseudo-classes - cannot be evaluated
855
+ userAction: new Set([
856
+ ':hover', ':active', ':focus', ':focus-within', ':focus-visible'
857
+ ]),
858
+ // Tree-structural pseudo-classes - can sometimes be evaluated
859
+ treeStructural: new Set([
860
+ ':root', ':empty', ':first-child', ':last-child', ':only-child',
861
+ ':first-of-type', ':last-of-type', ':only-of-type',
862
+ ':nth-child', ':nth-last-child', ':nth-of-type', ':nth-last-of-type'
863
+ ]),
864
+ // Link pseudo-classes
865
+ link: new Set([
866
+ ':link', ':visited', ':any-link', ':local-link', ':target'
867
+ ]),
868
+ // Input pseudo-classes
869
+ input: new Set([
870
+ ':enabled', ':disabled', ':read-only', ':read-write', ':placeholder-shown',
871
+ ':default', ':checked', ':indeterminate', ':valid', ':invalid', ':in-range',
872
+ ':out-of-range', ':required', ':optional'
873
+ ]),
874
+ // Linguistic pseudo-classes
875
+ linguistic: new Set([
876
+ ':lang', ':dir'
877
+ ]),
878
+ // Negation and matching
879
+ functional: new Set([
880
+ ':not', ':is', ':where', ':has'
881
+ ]),
882
+ // All pseudo-classes that prevent inlining
883
+ preventInlining: new Set([
884
+ ':hover', ':active', ':focus', ':focus-within', ':focus-visible',
885
+ ':visited', ':target', ':lang', ':dir', ':not', ':is', ':where', ':has'
886
+ ])
887
+ };
888
+
889
+ // ============================================================================
890
+ // EXPANDED EDITOR NAMESPACES
891
+ // ============================================================================
892
+
893
+ /**
894
+ * Additional editor namespaces beyond the base set
895
+ */
896
+ export const additionalEditorNamespaces = new Set([
897
+ // CorelDraw
898
+ 'http://www.corel.com/coreldraw/svg',
899
+ // Gravit Designer
900
+ 'http://gravit.io/ns',
901
+ // Affinity
902
+ 'http://serif.com/affinity',
903
+ // Canva
904
+ 'http://canva.com/ns',
905
+ ]);
906
+
907
+ // Merge additional namespaces into main set at initialization (avoid post-export mutation)
908
+ for (const ns of additionalEditorNamespaces) {
909
+ editorNamespaces.add(ns);
910
+ }