@eturnity/dom_to_svg 8.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +47 -0
- package/lib/accessibility.d.ts +3 -0
- package/lib/accessibility.d.ts.map +1 -0
- package/lib/accessibility.js +201 -0
- package/lib/accessibility.js.map +1 -0
- package/lib/css.d.ts +26 -0
- package/lib/css.d.ts.map +1 -0
- package/lib/css.js +96 -0
- package/lib/css.js.map +1 -0
- package/lib/dom.d.ts +22 -0
- package/lib/dom.d.ts.map +1 -0
- package/lib/dom.js +33 -0
- package/lib/dom.js.map +1 -0
- package/lib/element.d.ts +3 -0
- package/lib/element.d.ts.map +1 -0
- package/lib/element.js +417 -0
- package/lib/element.js.map +1 -0
- package/lib/gradients.d.ts +3 -0
- package/lib/gradients.d.ts.map +1 -0
- package/lib/gradients.js +78 -0
- package/lib/gradients.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +75 -0
- package/lib/index.js.map +1 -0
- package/lib/inline.d.ts +14 -0
- package/lib/inline.d.ts.map +1 -0
- package/lib/inline.js +138 -0
- package/lib/inline.js.map +1 -0
- package/lib/stacking.d.ts +38 -0
- package/lib/stacking.d.ts.map +1 -0
- package/lib/stacking.js +125 -0
- package/lib/stacking.js.map +1 -0
- package/lib/svg.d.ts +14 -0
- package/lib/svg.d.ts.map +1 -0
- package/lib/svg.js +245 -0
- package/lib/svg.js.map +1 -0
- package/lib/test/PuppeteerAdapter.d.ts +90 -0
- package/lib/test/PuppeteerAdapter.d.ts.map +1 -0
- package/lib/test/PuppeteerAdapter.js +196 -0
- package/lib/test/PuppeteerAdapter.js.map +1 -0
- package/lib/test/injected-script.d.ts +2 -0
- package/lib/test/injected-script.d.ts.map +1 -0
- package/lib/test/injected-script.js +26 -0
- package/lib/test/injected-script.js.map +1 -0
- package/lib/test/test.d.ts +6 -0
- package/lib/test/test.d.ts.map +1 -0
- package/lib/test/test.js +245 -0
- package/lib/test/test.js.map +1 -0
- package/lib/test/util.d.ts +9 -0
- package/lib/test/util.d.ts.map +1 -0
- package/lib/test/util.js +33 -0
- package/lib/test/util.js.map +1 -0
- package/lib/text.d.ts +5 -0
- package/lib/text.d.ts.map +1 -0
- package/lib/text.js +138 -0
- package/lib/text.js.map +1 -0
- package/lib/traversal.d.ts +32 -0
- package/lib/traversal.d.ts.map +1 -0
- package/lib/traversal.js +12 -0
- package/lib/traversal.js.map +1 -0
- package/lib/util.d.ts +20 -0
- package/lib/util.d.ts.map +1 -0
- package/lib/util.js +43 -0
- package/lib/util.js.map +1 -0
- package/package.json +112 -0
package/lib/element.js
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import cssValueParser from 'postcss-value-parser';
|
|
2
|
+
import { getAccessibilityAttributes } from './accessibility.js';
|
|
3
|
+
import { copyCssStyles, isVisible, isTransparent, hasUniformBorder, parseCSSLength, unescapeStringValue, getBorderRadiiForSide, calculateOverlappingCurvesFactor, } from './css.js';
|
|
4
|
+
import { svgNamespace, isHTMLAnchorElement, isHTMLImageElement, isHTMLInputElement, isHTMLElement, isSVGSVGElement, } from './dom.js';
|
|
5
|
+
import { convertLinearGradient } from './gradients.js';
|
|
6
|
+
import { createStackingLayers, establishesStackingContext, determineStackingLayer, sortStackingLayerChildren, cleanupStackingLayerChildren, } from './stacking.js';
|
|
7
|
+
import { handleSvgNode } from './svg.js';
|
|
8
|
+
import { copyTextStyles } from './text.js';
|
|
9
|
+
import { walkNode } from './traversal.js';
|
|
10
|
+
import { doRectanglesIntersect, isTaggedUnionMember } from './util.js';
|
|
11
|
+
export function handleElement(element, context) {
|
|
12
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
13
|
+
const cleanupFunctions = [];
|
|
14
|
+
try {
|
|
15
|
+
const window = element.ownerDocument.defaultView;
|
|
16
|
+
if (!window) {
|
|
17
|
+
throw new Error("Element's ownerDocument has no defaultView");
|
|
18
|
+
}
|
|
19
|
+
const bounds = element.getBoundingClientRect(); // Includes borders
|
|
20
|
+
const rectanglesIntersect = doRectanglesIntersect(bounds, context.options.captureArea);
|
|
21
|
+
const styles = window.getComputedStyle(element);
|
|
22
|
+
const parentStyles = element.parentElement && window.getComputedStyle(element.parentElement);
|
|
23
|
+
const svgContainer = isHTMLAnchorElement(element) && context.options.keepLinks
|
|
24
|
+
? createSvgAnchor(element, context)
|
|
25
|
+
: context.svgDocument.createElementNS(svgNamespace, 'g');
|
|
26
|
+
// Add IDs, classes, debug info
|
|
27
|
+
svgContainer.dataset.tag = element.tagName.toLowerCase();
|
|
28
|
+
const id = element.id || context.getUniqueId(element.classList[0] || element.tagName.toLowerCase());
|
|
29
|
+
svgContainer.id = id;
|
|
30
|
+
const className = element.getAttribute('class');
|
|
31
|
+
if (className) {
|
|
32
|
+
svgContainer.setAttribute('class', className);
|
|
33
|
+
}
|
|
34
|
+
// Title
|
|
35
|
+
if (isHTMLElement(element) && element.title) {
|
|
36
|
+
const svgTitle = context.svgDocument.createElementNS(svgNamespace, 'title');
|
|
37
|
+
svgTitle.textContent = element.title;
|
|
38
|
+
svgContainer.prepend(svgTitle);
|
|
39
|
+
}
|
|
40
|
+
// Which parent should the container itself be appended to?
|
|
41
|
+
const stackingLayerName = determineStackingLayer(styles, parentStyles);
|
|
42
|
+
const stackingLayer = stackingLayerName
|
|
43
|
+
? context.stackingLayers[stackingLayerName]
|
|
44
|
+
: context.parentStackingLayer;
|
|
45
|
+
if (stackingLayer) {
|
|
46
|
+
context.currentSvgParent.setAttribute('aria-owns', [context.currentSvgParent.getAttribute('aria-owns'), svgContainer.id].filter(Boolean).join(' '));
|
|
47
|
+
}
|
|
48
|
+
// If the parent is within the same stacking layer, append to the parent.
|
|
49
|
+
// Otherwise append to the right stacking layer.
|
|
50
|
+
const elementToAppendTo = context.parentStackingLayer === stackingLayer ? context.currentSvgParent : stackingLayer;
|
|
51
|
+
svgContainer.dataset.zIndex = styles.zIndex; // Used for sorting
|
|
52
|
+
elementToAppendTo.append(svgContainer);
|
|
53
|
+
// If the element establishes a stacking context, create subgroups for each stacking layer.
|
|
54
|
+
let childContext;
|
|
55
|
+
let backgroundContainer;
|
|
56
|
+
let ownStackingLayers;
|
|
57
|
+
if (establishesStackingContext(styles, parentStyles)) {
|
|
58
|
+
ownStackingLayers = createStackingLayers(svgContainer);
|
|
59
|
+
backgroundContainer = ownStackingLayers.rootBackgroundAndBorders;
|
|
60
|
+
childContext = {
|
|
61
|
+
...context,
|
|
62
|
+
currentSvgParent: svgContainer,
|
|
63
|
+
stackingLayers: ownStackingLayers,
|
|
64
|
+
parentStackingLayer: stackingLayer,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
backgroundContainer = svgContainer;
|
|
69
|
+
childContext = {
|
|
70
|
+
...context,
|
|
71
|
+
currentSvgParent: svgContainer,
|
|
72
|
+
parentStackingLayer: stackingLayer,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Opacity
|
|
76
|
+
if (styles.opacity !== '1') {
|
|
77
|
+
svgContainer.setAttribute('opacity', styles.opacity);
|
|
78
|
+
}
|
|
79
|
+
// Accessibility
|
|
80
|
+
for (const [name, value] of getAccessibilityAttributes(element, context)) {
|
|
81
|
+
svgContainer.setAttribute(name, value);
|
|
82
|
+
}
|
|
83
|
+
// Handle ::before and ::after by creating temporary child elements in the DOM.
|
|
84
|
+
// Avoid infinite loop, in case `element` already is already a synthetic element created by us for a pseudo element.
|
|
85
|
+
if (isHTMLElement(element) && !element.dataset.pseudoElement) {
|
|
86
|
+
const handlePseudoElement = (pseudoSelector, position) => {
|
|
87
|
+
const pseudoElementStyles = window.getComputedStyle(element, pseudoSelector);
|
|
88
|
+
const content = cssValueParser(pseudoElementStyles.content).nodes.find(isTaggedUnionMember('type', 'string'));
|
|
89
|
+
if (!content) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Pseudo elements are inline by default (like a span)
|
|
93
|
+
const span = element.ownerDocument.createElement('span');
|
|
94
|
+
span.dataset.pseudoElement = pseudoSelector;
|
|
95
|
+
copyCssStyles(pseudoElementStyles, span.style);
|
|
96
|
+
span.textContent = unescapeStringValue(content.value);
|
|
97
|
+
element.dataset.pseudoElementOwner = id;
|
|
98
|
+
cleanupFunctions.push(() => element.removeAttribute('data-pseudo-element-owner'));
|
|
99
|
+
const style = element.ownerDocument.createElement('style');
|
|
100
|
+
// Hide the *actual* pseudo element temporarily while we have a real DOM equivalent in the DOM
|
|
101
|
+
style.textContent = `[data-pseudo-element-owner="${id}"]${pseudoSelector} { display: none !important; }`;
|
|
102
|
+
element.before(style);
|
|
103
|
+
cleanupFunctions.push(() => style.remove());
|
|
104
|
+
element[position](span);
|
|
105
|
+
cleanupFunctions.push(() => span.remove());
|
|
106
|
+
};
|
|
107
|
+
handlePseudoElement('::before', 'prepend');
|
|
108
|
+
handlePseudoElement('::after', 'append');
|
|
109
|
+
// TODO handle ::marker etc
|
|
110
|
+
}
|
|
111
|
+
if (rectanglesIntersect) {
|
|
112
|
+
addBackgroundAndBorders(styles, bounds, backgroundContainer, window, context);
|
|
113
|
+
}
|
|
114
|
+
// If element is overflow: hidden, create a masking rectangle to hide any overflowing content of any descendants.
|
|
115
|
+
// Use <mask> instead of <clipPath> as Figma supports <mask>, but not <clipPath>.
|
|
116
|
+
if (styles.overflow !== 'visible') {
|
|
117
|
+
const mask = context.svgDocument.createElementNS(svgNamespace, 'mask');
|
|
118
|
+
mask.id = context.getUniqueId('mask-for-' + id);
|
|
119
|
+
const visibleRectangle = createBox(bounds, context);
|
|
120
|
+
visibleRectangle.setAttribute('fill', '#ffffff');
|
|
121
|
+
mask.append(visibleRectangle);
|
|
122
|
+
svgContainer.append(mask);
|
|
123
|
+
svgContainer.setAttribute('mask', `url(#${mask.id})`);
|
|
124
|
+
childContext = {
|
|
125
|
+
...childContext,
|
|
126
|
+
ancestorMasks: [{ mask, forElement: element }, ...childContext.ancestorMasks],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (isHTMLElement(element) &&
|
|
130
|
+
(styles.position === 'absolute' || styles.position === 'fixed') &&
|
|
131
|
+
context.ancestorMasks.length > 0 &&
|
|
132
|
+
element.offsetParent) {
|
|
133
|
+
// Absolute and fixed elements are out of the flow and will bleed out of an `overflow: hidden` ancestor
|
|
134
|
+
// as long as their offsetParent is higher up than the mask element.
|
|
135
|
+
for (const { mask, forElement } of context.ancestorMasks) {
|
|
136
|
+
if (element.offsetParent.contains(forElement) || element.offsetParent === forElement) {
|
|
137
|
+
// Add a cutout to the ancestor mask
|
|
138
|
+
const visibleRectangle = createBox(bounds, context);
|
|
139
|
+
visibleRectangle.setAttribute('fill', '#ffffff');
|
|
140
|
+
mask.append(visibleRectangle);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (rectanglesIntersect &&
|
|
148
|
+
isHTMLImageElement(element) &&
|
|
149
|
+
// Make sure the element has a src/srcset attribute (the relative URL). `element.src` is absolute and always defined.
|
|
150
|
+
(element.getAttribute('src') || element.getAttribute('srcset'))) {
|
|
151
|
+
const svgImage = context.svgDocument.createElementNS(svgNamespace, 'image');
|
|
152
|
+
svgImage.id = `${id}-image`; // read by inlineResources()
|
|
153
|
+
svgImage.setAttribute('xlink:href', element.currentSrc || element.src);
|
|
154
|
+
const paddingLeft = (_a = parseCSSLength(styles.paddingLeft, bounds.width)) !== null && _a !== void 0 ? _a : 0;
|
|
155
|
+
const paddingRight = (_b = parseCSSLength(styles.paddingRight, bounds.width)) !== null && _b !== void 0 ? _b : 0;
|
|
156
|
+
const paddingTop = (_c = parseCSSLength(styles.paddingTop, bounds.height)) !== null && _c !== void 0 ? _c : 0;
|
|
157
|
+
const paddingBottom = (_d = parseCSSLength(styles.paddingBottom, bounds.height)) !== null && _d !== void 0 ? _d : 0;
|
|
158
|
+
svgImage.setAttribute('x', (bounds.x + paddingLeft).toString());
|
|
159
|
+
svgImage.setAttribute('y', (bounds.y + paddingTop).toString());
|
|
160
|
+
svgImage.setAttribute('width', (bounds.width - paddingLeft - paddingRight).toString());
|
|
161
|
+
svgImage.setAttribute('height', (bounds.height - paddingTop - paddingBottom).toString());
|
|
162
|
+
if (element.alt) {
|
|
163
|
+
svgImage.setAttribute('aria-label', element.alt);
|
|
164
|
+
}
|
|
165
|
+
svgContainer.append(svgImage);
|
|
166
|
+
}
|
|
167
|
+
else if (rectanglesIntersect && isHTMLInputElement(element) && bounds.width > 0 && bounds.height > 0) {
|
|
168
|
+
// Handle button labels or input field content
|
|
169
|
+
if (element.value) {
|
|
170
|
+
const svgTextElement = context.svgDocument.createElementNS(svgNamespace, 'text');
|
|
171
|
+
copyTextStyles(styles, svgTextElement);
|
|
172
|
+
svgTextElement.setAttribute('dominant-baseline', 'central');
|
|
173
|
+
svgTextElement.setAttribute('xml:space', 'preserve');
|
|
174
|
+
svgTextElement.setAttribute('x', (bounds.x + ((_e = parseCSSLength(styles.paddingLeft, bounds.width)) !== null && _e !== void 0 ? _e : 0)).toString());
|
|
175
|
+
const top = bounds.top + ((_f = parseCSSLength(styles.paddingTop, bounds.height)) !== null && _f !== void 0 ? _f : 0);
|
|
176
|
+
const bottom = bounds.bottom + ((_g = parseCSSLength(styles.paddingBottom, bounds.height)) !== null && _g !== void 0 ? _g : 0);
|
|
177
|
+
const middle = (top + bottom) / 2;
|
|
178
|
+
svgTextElement.setAttribute('y', middle.toString());
|
|
179
|
+
svgTextElement.textContent = element.value;
|
|
180
|
+
childContext.stackingLayers.inFlowInlineLevelNonPositionedDescendants.append(svgTextElement);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (rectanglesIntersect && isSVGSVGElement(element) && isVisible(styles)) {
|
|
184
|
+
handleSvgNode(element, { ...childContext, idPrefix: `${id}-` });
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
// Walk children even if rectangles don't intersect,
|
|
188
|
+
// because children can overflow the parent's bounds as long as overflow: visible (default).
|
|
189
|
+
for (const child of element.childNodes) {
|
|
190
|
+
walkNode(child, childContext);
|
|
191
|
+
}
|
|
192
|
+
if (ownStackingLayers) {
|
|
193
|
+
sortStackingLayerChildren(ownStackingLayers);
|
|
194
|
+
cleanupStackingLayerChildren(ownStackingLayers);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
for (const cleanup of cleanupFunctions) {
|
|
200
|
+
cleanup();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function addBackgroundAndBorders(styles, bounds, backgroundAndBordersContainer, window, context) {
|
|
205
|
+
var _a, _b, _c, _d;
|
|
206
|
+
if (isVisible(styles)) {
|
|
207
|
+
if (bounds.width > 0 &&
|
|
208
|
+
bounds.height > 0 &&
|
|
209
|
+
(!isTransparent(styles.backgroundColor) || hasUniformBorder(styles) || styles.backgroundImage !== 'none')) {
|
|
210
|
+
const box = createBackgroundAndBorderBox(bounds, styles, context);
|
|
211
|
+
backgroundAndBordersContainer.append(box);
|
|
212
|
+
if (styles.backgroundImage !== 'none') {
|
|
213
|
+
const backgrounds = cssValueParser(styles.backgroundImage)
|
|
214
|
+
.nodes.filter(isTaggedUnionMember('type', 'function'))
|
|
215
|
+
.reverse();
|
|
216
|
+
const xBackgroundPositions = styles.backgroundPositionX.split(/\s*,\s*/g);
|
|
217
|
+
const yBackgroundPositions = styles.backgroundPositionY.split(/\s*,\s*/g);
|
|
218
|
+
const backgroundRepeats = styles.backgroundRepeat.split(/\s*,\s*/g);
|
|
219
|
+
for (const [index, backgroundNode] of backgrounds.entries()) {
|
|
220
|
+
const backgroundPositionX = (_a = parseCSSLength(xBackgroundPositions[index], bounds.width)) !== null && _a !== void 0 ? _a : 0;
|
|
221
|
+
const backgroundPositionY = (_b = parseCSSLength(yBackgroundPositions[index], bounds.height)) !== null && _b !== void 0 ? _b : 0;
|
|
222
|
+
const backgroundRepeat = backgroundRepeats[index];
|
|
223
|
+
if (backgroundNode.value === 'url' && backgroundNode.nodes[0]) {
|
|
224
|
+
const urlArgument = backgroundNode.nodes[0];
|
|
225
|
+
const image = context.svgDocument.createElementNS(svgNamespace, 'image');
|
|
226
|
+
image.id = context.getUniqueId('background-image'); // read by inlineResources()
|
|
227
|
+
const [cssWidth = 'auto', cssHeight = 'auto'] = styles.backgroundSize.split(' ');
|
|
228
|
+
const backgroundWidth = (_c = parseCSSLength(cssWidth, bounds.width)) !== null && _c !== void 0 ? _c : bounds.width;
|
|
229
|
+
const backgroundHeight = (_d = parseCSSLength(cssHeight, bounds.height)) !== null && _d !== void 0 ? _d : bounds.height;
|
|
230
|
+
image.setAttribute('width', backgroundWidth.toString());
|
|
231
|
+
image.setAttribute('height', backgroundHeight.toString());
|
|
232
|
+
if (cssWidth !== 'auto' && cssHeight !== 'auto') {
|
|
233
|
+
image.setAttribute('preserveAspectRatio', 'none');
|
|
234
|
+
}
|
|
235
|
+
else if (styles.backgroundSize === 'contain') {
|
|
236
|
+
image.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
|
237
|
+
}
|
|
238
|
+
else if (styles.backgroundSize === 'cover') {
|
|
239
|
+
image.setAttribute('preserveAspectRatio', 'xMidYMid slice');
|
|
240
|
+
}
|
|
241
|
+
// Technically not correct, because relative URLs should be resolved relative to the stylesheet,
|
|
242
|
+
// not the page. But we have no means to know what stylesheet the style came from
|
|
243
|
+
// (unless we iterate through all rules in all style sheets and find the matching one).
|
|
244
|
+
const url = new URL(unescapeStringValue(urlArgument.value), window.location.href);
|
|
245
|
+
image.setAttribute('xlink:href', url.href);
|
|
246
|
+
if (backgroundRepeat === 'no-repeat' ||
|
|
247
|
+
(backgroundPositionX === 0 &&
|
|
248
|
+
backgroundPositionY === 0 &&
|
|
249
|
+
backgroundWidth === bounds.width &&
|
|
250
|
+
backgroundHeight === bounds.height)) {
|
|
251
|
+
image.setAttribute('x', bounds.x.toString());
|
|
252
|
+
image.setAttribute('y', bounds.y.toString());
|
|
253
|
+
backgroundAndBordersContainer.append(image);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
image.setAttribute('x', '0');
|
|
257
|
+
image.setAttribute('y', '0');
|
|
258
|
+
const pattern = context.svgDocument.createElementNS(svgNamespace, 'pattern');
|
|
259
|
+
pattern.setAttribute('patternUnits', 'userSpaceOnUse');
|
|
260
|
+
pattern.setAttribute('patternContentUnits', 'userSpaceOnUse');
|
|
261
|
+
pattern.setAttribute('x', (bounds.x + backgroundPositionX).toString());
|
|
262
|
+
pattern.setAttribute('y', (bounds.y + backgroundPositionY).toString());
|
|
263
|
+
pattern.setAttribute('width', (backgroundRepeat === 'repeat' || backgroundRepeat === 'repeat-x'
|
|
264
|
+
? backgroundWidth
|
|
265
|
+
: // If background shouldn't repeat on this axis, make the tile as big as the element so the repetition is cut off.
|
|
266
|
+
backgroundWidth + bounds.x + backgroundPositionX).toString());
|
|
267
|
+
pattern.setAttribute('height', (backgroundRepeat === 'repeat' || backgroundRepeat === 'repeat-y'
|
|
268
|
+
? backgroundHeight
|
|
269
|
+
: // If background shouldn't repeat on this axis, make the tile as big as the element so the repetition is cut off.
|
|
270
|
+
backgroundHeight + bounds.y + backgroundPositionY).toString());
|
|
271
|
+
pattern.id = context.getUniqueId('pattern');
|
|
272
|
+
pattern.append(image);
|
|
273
|
+
box.before(pattern);
|
|
274
|
+
box.setAttribute('fill', `url(#${pattern.id})`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else if (/^(-webkit-)?linear-gradient$/.test(backgroundNode.value)) {
|
|
278
|
+
const linearGradientCss = cssValueParser.stringify(backgroundNode);
|
|
279
|
+
const svgLinearGradient = convertLinearGradient(linearGradientCss, context);
|
|
280
|
+
if (backgroundPositionX !== 0 || backgroundPositionY !== 0) {
|
|
281
|
+
svgLinearGradient.setAttribute('gradientTransform', `translate(${backgroundPositionX}, ${backgroundPositionY})`);
|
|
282
|
+
}
|
|
283
|
+
svgLinearGradient.id = context.getUniqueId('linear-gradient');
|
|
284
|
+
box.before(svgLinearGradient);
|
|
285
|
+
box.setAttribute('fill', `url(#${svgLinearGradient.id})`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (!hasUniformBorder(styles)) {
|
|
291
|
+
// Draw lines for each border
|
|
292
|
+
for (const borderLine of createBorders(styles, bounds, context)) {
|
|
293
|
+
backgroundAndBordersContainer.append(borderLine);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function createBox(bounds, context) {
|
|
299
|
+
const box = context.svgDocument.createElementNS(svgNamespace, 'rect');
|
|
300
|
+
// TODO consider rotation
|
|
301
|
+
box.setAttribute('width', bounds.width.toString());
|
|
302
|
+
box.setAttribute('height', bounds.height.toString());
|
|
303
|
+
box.setAttribute('x', bounds.x.toString());
|
|
304
|
+
box.setAttribute('y', bounds.y.toString());
|
|
305
|
+
return box;
|
|
306
|
+
}
|
|
307
|
+
function createBackgroundAndBorderBox(bounds, styles, context) {
|
|
308
|
+
const background = createBox(bounds, context);
|
|
309
|
+
// TODO handle background image and other properties
|
|
310
|
+
if (styles.backgroundColor) {
|
|
311
|
+
background.setAttribute('fill', styles.backgroundColor);
|
|
312
|
+
}
|
|
313
|
+
if (hasUniformBorder(styles)) {
|
|
314
|
+
// Uniform border, use stroke
|
|
315
|
+
// Cannot use borderColor/borderWidth directly as in Firefox those are empty strings.
|
|
316
|
+
// Need to get the border property from some specific side (they are all the same in this condition).
|
|
317
|
+
// https://stackoverflow.com/questions/41696063/getcomputedstyle-returns-empty-strings-on-ff-when-instead-crome-returns-a-comp
|
|
318
|
+
background.setAttribute('stroke', styles.borderTopColor);
|
|
319
|
+
background.setAttribute('stroke-width', styles.borderTopWidth);
|
|
320
|
+
if (styles.borderTopStyle === 'dashed') {
|
|
321
|
+
// > Displays a series of short square-ended dashes or line segments.
|
|
322
|
+
// > The exact size and length of the segments are not defined by the specification and are implementation-specific.
|
|
323
|
+
background.setAttribute('stroke-dasharray', '1');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Set border radius
|
|
327
|
+
// Approximation, always assumes uniform border-radius by using the top-left horizontal radius and the top-left vertical radius for all corners.
|
|
328
|
+
// TODO support irregular border radii on all corners by drawing border as a <path>.
|
|
329
|
+
const overlappingCurvesFactor = calculateOverlappingCurvesFactor(styles, bounds);
|
|
330
|
+
const radiusX = getBorderRadiiForSide('top', styles, bounds)[0] * overlappingCurvesFactor;
|
|
331
|
+
const radiusY = getBorderRadiiForSide('left', styles, bounds)[0] * overlappingCurvesFactor;
|
|
332
|
+
if (radiusX !== 0) {
|
|
333
|
+
background.setAttribute('rx', radiusX.toString());
|
|
334
|
+
}
|
|
335
|
+
if (radiusY !== 0) {
|
|
336
|
+
background.setAttribute('ry', radiusY.toString());
|
|
337
|
+
}
|
|
338
|
+
return background;
|
|
339
|
+
}
|
|
340
|
+
function* createBorders(styles, bounds, context) {
|
|
341
|
+
for (const side of ['top', 'bottom', 'right', 'left']) {
|
|
342
|
+
if (hasBorder(styles, side)) {
|
|
343
|
+
yield createBorder(styles, bounds, side, context);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function hasBorder(styles, side) {
|
|
348
|
+
return (!!styles.getPropertyValue(`border-${side}-color`) &&
|
|
349
|
+
!isTransparent(styles.getPropertyValue(`border-${side}-color`)) &&
|
|
350
|
+
styles.getPropertyValue(`border-${side}-width`) !== '0px');
|
|
351
|
+
}
|
|
352
|
+
function createBorder(styles, bounds, side, context) {
|
|
353
|
+
// TODO handle border-radius for non-uniform borders
|
|
354
|
+
const border = context.svgDocument.createElementNS(svgNamespace, 'line');
|
|
355
|
+
border.setAttribute('stroke-linecap', 'square');
|
|
356
|
+
const color = styles.getPropertyValue(`border-${side}-color`);
|
|
357
|
+
border.setAttribute('stroke', color);
|
|
358
|
+
border.setAttribute('stroke-width', styles.getPropertyValue(`border-${side}-width`));
|
|
359
|
+
// Handle inset/outset borders
|
|
360
|
+
const borderStyle = styles.getPropertyValue(`border-${side}-style`);
|
|
361
|
+
if ((borderStyle === 'inset' && (side === 'top' || side === 'left')) ||
|
|
362
|
+
(borderStyle === 'outset' && (side === 'right' || side === 'bottom'))) {
|
|
363
|
+
const match = color.match(/rgba?\((\d+), (\d+), (\d+)(?:, ([\d.]+))?\)/);
|
|
364
|
+
if (!match) {
|
|
365
|
+
throw new Error(`Unexpected color: ${color}`);
|
|
366
|
+
}
|
|
367
|
+
const components = match.slice(1, 4).map(value => parseInt(value, 10) * 0.3);
|
|
368
|
+
if (match[4]) {
|
|
369
|
+
components.push(parseFloat(match[4]));
|
|
370
|
+
}
|
|
371
|
+
// Low-light border
|
|
372
|
+
// https://stackoverflow.com/questions/4147940/how-do-browsers-determine-which-exact-colors-to-use-for-border-inset-or-outset
|
|
373
|
+
border.setAttribute('stroke', `rgba(${components.join(', ')})`);
|
|
374
|
+
}
|
|
375
|
+
if (side === 'top') {
|
|
376
|
+
border.setAttribute('x1', bounds.left.toString());
|
|
377
|
+
border.setAttribute('x2', bounds.right.toString());
|
|
378
|
+
border.setAttribute('y1', bounds.top.toString());
|
|
379
|
+
border.setAttribute('y2', bounds.top.toString());
|
|
380
|
+
}
|
|
381
|
+
else if (side === 'left') {
|
|
382
|
+
border.setAttribute('x1', bounds.left.toString());
|
|
383
|
+
border.setAttribute('x2', bounds.left.toString());
|
|
384
|
+
border.setAttribute('y1', bounds.top.toString());
|
|
385
|
+
border.setAttribute('y2', bounds.bottom.toString());
|
|
386
|
+
}
|
|
387
|
+
else if (side === 'right') {
|
|
388
|
+
border.setAttribute('x1', bounds.right.toString());
|
|
389
|
+
border.setAttribute('x2', bounds.right.toString());
|
|
390
|
+
border.setAttribute('y1', bounds.top.toString());
|
|
391
|
+
border.setAttribute('y2', bounds.bottom.toString());
|
|
392
|
+
}
|
|
393
|
+
else if (side === 'bottom') {
|
|
394
|
+
border.setAttribute('x1', bounds.left.toString());
|
|
395
|
+
border.setAttribute('x2', bounds.right.toString());
|
|
396
|
+
border.setAttribute('y1', bounds.bottom.toString());
|
|
397
|
+
border.setAttribute('y2', bounds.bottom.toString());
|
|
398
|
+
}
|
|
399
|
+
return border;
|
|
400
|
+
}
|
|
401
|
+
function createSvgAnchor(element, context) {
|
|
402
|
+
const svgAnchor = context.svgDocument.createElementNS(svgNamespace, 'a');
|
|
403
|
+
if (element.href && !element.href.startsWith('javascript:')) {
|
|
404
|
+
svgAnchor.setAttribute('href', element.href);
|
|
405
|
+
}
|
|
406
|
+
if (element.rel) {
|
|
407
|
+
svgAnchor.setAttribute('rel', element.rel);
|
|
408
|
+
}
|
|
409
|
+
if (element.target) {
|
|
410
|
+
svgAnchor.setAttribute('target', element.target);
|
|
411
|
+
}
|
|
412
|
+
if (element.download) {
|
|
413
|
+
svgAnchor.setAttribute('download', element.download);
|
|
414
|
+
}
|
|
415
|
+
return svgAnchor;
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"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","sourcesContent":["import cssValueParser from 'postcss-value-parser'\n\nimport { getAccessibilityAttributes } from './accessibility.js'\nimport {\n\tcopyCssStyles,\n\tisVisible,\n\tisTransparent,\n\thasUniformBorder,\n\tparseCSSLength,\n\tunescapeStringValue,\n\tSide,\n\tgetBorderRadiiForSide,\n\tcalculateOverlappingCurvesFactor,\n} from './css.js'\nimport {\n\tsvgNamespace,\n\tisHTMLAnchorElement,\n\tisHTMLImageElement,\n\tisHTMLInputElement,\n\tisHTMLElement,\n\tisSVGSVGElement,\n} from './dom.js'\nimport { convertLinearGradient } from './gradients.js'\nimport {\n\tcreateStackingLayers,\n\testablishesStackingContext,\n\tdetermineStackingLayer,\n\tStackingLayers,\n\tsortStackingLayerChildren,\n\tcleanupStackingLayerChildren,\n} from './stacking.js'\nimport { handleSvgNode } from './svg.js'\nimport { copyTextStyles } from './text.js'\nimport { TraversalContext, walkNode } from './traversal.js'\nimport { doRectanglesIntersect, isTaggedUnionMember } from './util.js'\n\nexport function handleElement(element: Element, context: Readonly<TraversalContext>): void {\n\tconst cleanupFunctions: (() => void)[] = []\n\n\ttry {\n\t\tconst window = element.ownerDocument.defaultView\n\t\tif (!window) {\n\t\t\tthrow new Error(\"Element's ownerDocument has no defaultView\")\n\t\t}\n\n\t\tconst bounds = element.getBoundingClientRect() // Includes borders\n\t\tconst rectanglesIntersect = doRectanglesIntersect(bounds, context.options.captureArea)\n\n\t\tconst styles = window.getComputedStyle(element)\n\t\tconst parentStyles = element.parentElement && window.getComputedStyle(element.parentElement)\n\n\t\tconst svgContainer =\n\t\t\tisHTMLAnchorElement(element) && context.options.keepLinks\n\t\t\t\t? createSvgAnchor(element, context)\n\t\t\t\t: context.svgDocument.createElementNS(svgNamespace, 'g')\n\n\t\t// Add IDs, classes, debug info\n\t\tsvgContainer.dataset.tag = element.tagName.toLowerCase()\n\t\tconst id = element.id || context.getUniqueId(element.classList[0] || element.tagName.toLowerCase())\n\t\tsvgContainer.id = id\n\t\tconst className = element.getAttribute('class')\n\t\tif (className) {\n\t\t\tsvgContainer.setAttribute('class', className)\n\t\t}\n\n\t\t// Title\n\t\tif (isHTMLElement(element) && element.title) {\n\t\t\tconst svgTitle = context.svgDocument.createElementNS(svgNamespace, 'title')\n\t\t\tsvgTitle.textContent = element.title\n\t\t\tsvgContainer.prepend(svgTitle)\n\t\t}\n\n\t\t// Which parent should the container itself be appended to?\n\t\tconst stackingLayerName = determineStackingLayer(styles, parentStyles)\n\t\tconst stackingLayer = stackingLayerName\n\t\t\t? context.stackingLayers[stackingLayerName]\n\t\t\t: context.parentStackingLayer\n\t\tif (stackingLayer) {\n\t\t\tcontext.currentSvgParent.setAttribute(\n\t\t\t\t'aria-owns',\n\t\t\t\t[context.currentSvgParent.getAttribute('aria-owns'), svgContainer.id].filter(Boolean).join(' ')\n\t\t\t)\n\t\t}\n\t\t// If the parent is within the same stacking layer, append to the parent.\n\t\t// Otherwise append to the right stacking layer.\n\t\tconst elementToAppendTo =\n\t\t\tcontext.parentStackingLayer === stackingLayer ? context.currentSvgParent : stackingLayer\n\t\tsvgContainer.dataset.zIndex = styles.zIndex // Used for sorting\n\t\telementToAppendTo.append(svgContainer)\n\n\t\t// If the element establishes a stacking context, create subgroups for each stacking layer.\n\t\tlet childContext: TraversalContext\n\t\tlet backgroundContainer: SVGElement\n\t\tlet ownStackingLayers: StackingLayers | undefined\n\t\tif (establishesStackingContext(styles, parentStyles)) {\n\t\t\townStackingLayers = createStackingLayers(svgContainer)\n\t\t\tbackgroundContainer = ownStackingLayers.rootBackgroundAndBorders\n\t\t\tchildContext = {\n\t\t\t\t...context,\n\t\t\t\tcurrentSvgParent: svgContainer,\n\t\t\t\tstackingLayers: ownStackingLayers,\n\t\t\t\tparentStackingLayer: stackingLayer,\n\t\t\t}\n\t\t} else {\n\t\t\tbackgroundContainer = svgContainer\n\t\t\tchildContext = {\n\t\t\t\t...context,\n\t\t\t\tcurrentSvgParent: svgContainer,\n\t\t\t\tparentStackingLayer: stackingLayer,\n\t\t\t}\n\t\t}\n\n\t\t// Opacity\n\t\tif (styles.opacity !== '1') {\n\t\t\tsvgContainer.setAttribute('opacity', styles.opacity)\n\t\t}\n\n\t\t// Accessibility\n\t\tfor (const [name, value] of getAccessibilityAttributes(element, context)) {\n\t\t\tsvgContainer.setAttribute(name, value)\n\t\t}\n\n\t\t// Handle ::before and ::after by creating temporary child elements in the DOM.\n\t\t// Avoid infinite loop, in case `element` already is already a synthetic element created by us for a pseudo element.\n\t\tif (isHTMLElement(element) && !element.dataset.pseudoElement) {\n\t\t\tconst handlePseudoElement = (\n\t\t\t\tpseudoSelector: '::before' | '::after',\n\t\t\t\tposition: 'prepend' | 'append'\n\t\t\t): void => {\n\t\t\t\tconst pseudoElementStyles = window.getComputedStyle(element, pseudoSelector)\n\t\t\t\tconst content = cssValueParser(pseudoElementStyles.content).nodes.find(\n\t\t\t\t\tisTaggedUnionMember('type', 'string' as const)\n\t\t\t\t)\n\t\t\t\tif (!content) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Pseudo elements are inline by default (like a span)\n\t\t\t\tconst span = element.ownerDocument.createElement('span')\n\t\t\t\tspan.dataset.pseudoElement = pseudoSelector\n\t\t\t\tcopyCssStyles(pseudoElementStyles, span.style)\n\t\t\t\tspan.textContent = unescapeStringValue(content.value)\n\t\t\t\telement.dataset.pseudoElementOwner = id\n\t\t\t\tcleanupFunctions.push(() => element.removeAttribute('data-pseudo-element-owner'))\n\t\t\t\tconst style = element.ownerDocument.createElement('style')\n\t\t\t\t// Hide the *actual* pseudo element temporarily while we have a real DOM equivalent in the DOM\n\t\t\t\tstyle.textContent = `[data-pseudo-element-owner=\"${id}\"]${pseudoSelector} { display: none !important; }`\n\t\t\t\telement.before(style)\n\t\t\t\tcleanupFunctions.push(() => style.remove())\n\t\t\t\telement[position](span)\n\t\t\t\tcleanupFunctions.push(() => span.remove())\n\t\t\t}\n\t\t\thandlePseudoElement('::before', 'prepend')\n\t\t\thandlePseudoElement('::after', 'append')\n\t\t\t// TODO handle ::marker etc\n\t\t}\n\n\t\tif (rectanglesIntersect) {\n\t\t\taddBackgroundAndBorders(styles, bounds, backgroundContainer, window, context)\n\t\t}\n\n\t\t// If element is overflow: hidden, create a masking rectangle to hide any overflowing content of any descendants.\n\t\t// Use <mask> instead of <clipPath> as Figma supports <mask>, but not <clipPath>.\n\t\tif (styles.overflow !== 'visible') {\n\t\t\tconst mask = context.svgDocument.createElementNS(svgNamespace, 'mask')\n\t\t\tmask.id = context.getUniqueId('mask-for-' + id)\n\t\t\tconst visibleRectangle = createBox(bounds, context)\n\t\t\tvisibleRectangle.setAttribute('fill', '#ffffff')\n\t\t\tmask.append(visibleRectangle)\n\t\t\tsvgContainer.append(mask)\n\t\t\tsvgContainer.setAttribute('mask', `url(#${mask.id})`)\n\t\t\tchildContext = {\n\t\t\t\t...childContext,\n\t\t\t\tancestorMasks: [{ mask, forElement: element }, ...childContext.ancestorMasks],\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\tisHTMLElement(element) &&\n\t\t\t(styles.position === 'absolute' || styles.position === 'fixed') &&\n\t\t\tcontext.ancestorMasks.length > 0 &&\n\t\t\telement.offsetParent\n\t\t) {\n\t\t\t// Absolute and fixed elements are out of the flow and will bleed out of an `overflow: hidden` ancestor\n\t\t\t// as long as their offsetParent is higher up than the mask element.\n\t\t\tfor (const { mask, forElement } of context.ancestorMasks) {\n\t\t\t\tif (element.offsetParent.contains(forElement) || element.offsetParent === forElement) {\n\t\t\t\t\t// Add a cutout to the ancestor mask\n\t\t\t\t\tconst visibleRectangle = createBox(bounds, context)\n\t\t\t\t\tvisibleRectangle.setAttribute('fill', '#ffffff')\n\t\t\t\t\tmask.append(visibleRectangle)\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\trectanglesIntersect &&\n\t\t\tisHTMLImageElement(element) &&\n\t\t\t// Make sure the element has a src/srcset attribute (the relative URL). `element.src` is absolute and always defined.\n\t\t\t(element.getAttribute('src') || element.getAttribute('srcset'))\n\t\t) {\n\t\t\tconst svgImage = context.svgDocument.createElementNS(svgNamespace, 'image')\n\t\t\tsvgImage.id = `${id}-image` // read by inlineResources()\n\t\t\tsvgImage.setAttribute('xlink:href', element.currentSrc || element.src)\n\t\t\tconst paddingLeft = parseCSSLength(styles.paddingLeft, bounds.width) ?? 0\n\t\t\tconst paddingRight = parseCSSLength(styles.paddingRight, bounds.width) ?? 0\n\t\t\tconst paddingTop = parseCSSLength(styles.paddingTop, bounds.height) ?? 0\n\t\t\tconst paddingBottom = parseCSSLength(styles.paddingBottom, bounds.height) ?? 0\n\t\t\tsvgImage.setAttribute('x', (bounds.x + paddingLeft).toString())\n\t\t\tsvgImage.setAttribute('y', (bounds.y + paddingTop).toString())\n\t\t\tsvgImage.setAttribute('width', (bounds.width - paddingLeft - paddingRight).toString())\n\t\t\tsvgImage.setAttribute('height', (bounds.height - paddingTop - paddingBottom).toString())\n\t\t\tif (element.alt) {\n\t\t\t\tsvgImage.setAttribute('aria-label', element.alt)\n\t\t\t}\n\t\t\tsvgContainer.append(svgImage)\n\t\t} else if (rectanglesIntersect && isHTMLInputElement(element) && bounds.width > 0 && bounds.height > 0) {\n\t\t\t// Handle button labels or input field content\n\t\t\tif (element.value) {\n\t\t\t\tconst svgTextElement = context.svgDocument.createElementNS(svgNamespace, 'text')\n\t\t\t\tcopyTextStyles(styles, svgTextElement)\n\t\t\t\tsvgTextElement.setAttribute('dominant-baseline', 'central')\n\t\t\t\tsvgTextElement.setAttribute('xml:space', 'preserve')\n\t\t\t\tsvgTextElement.setAttribute(\n\t\t\t\t\t'x',\n\t\t\t\t\t(bounds.x + (parseCSSLength(styles.paddingLeft, bounds.width) ?? 0)).toString()\n\t\t\t\t)\n\t\t\t\tconst top = bounds.top + (parseCSSLength(styles.paddingTop, bounds.height) ?? 0)\n\t\t\t\tconst bottom = bounds.bottom + (parseCSSLength(styles.paddingBottom, bounds.height) ?? 0)\n\t\t\t\tconst middle = (top + bottom) / 2\n\t\t\t\tsvgTextElement.setAttribute('y', middle.toString())\n\t\t\t\tsvgTextElement.textContent = element.value\n\t\t\t\tchildContext.stackingLayers.inFlowInlineLevelNonPositionedDescendants.append(svgTextElement)\n\t\t\t}\n\t\t} else if (rectanglesIntersect && isSVGSVGElement(element) && isVisible(styles)) {\n\t\t\thandleSvgNode(element, { ...childContext, idPrefix: `${id}-` })\n\t\t} else {\n\t\t\t// Walk children even if rectangles don't intersect,\n\t\t\t// because children can overflow the parent's bounds as long as overflow: visible (default).\n\t\t\tfor (const child of element.childNodes) {\n\t\t\t\twalkNode(child, childContext)\n\t\t\t}\n\t\t\tif (ownStackingLayers) {\n\t\t\t\tsortStackingLayerChildren(ownStackingLayers)\n\t\t\t\tcleanupStackingLayerChildren(ownStackingLayers)\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tfor (const cleanup of cleanupFunctions) {\n\t\t\tcleanup()\n\t\t}\n\t}\n}\n\nfunction addBackgroundAndBorders(\n\tstyles: CSSStyleDeclaration,\n\tbounds: DOMRect,\n\tbackgroundAndBordersContainer: SVGElement,\n\twindow: Window,\n\tcontext: Pick<TraversalContext, 'getUniqueId' | 'svgDocument'>\n): void {\n\tif (isVisible(styles)) {\n\t\tif (\n\t\t\tbounds.width > 0 &&\n\t\t\tbounds.height > 0 &&\n\t\t\t(!isTransparent(styles.backgroundColor) || hasUniformBorder(styles) || styles.backgroundImage !== 'none')\n\t\t) {\n\t\t\tconst box = createBackgroundAndBorderBox(bounds, styles, context)\n\t\t\tbackgroundAndBordersContainer.append(box)\n\t\t\tif (styles.backgroundImage !== 'none') {\n\t\t\t\tconst backgrounds = cssValueParser(styles.backgroundImage)\n\t\t\t\t\t.nodes.filter(isTaggedUnionMember('type', 'function' as const))\n\t\t\t\t\t.reverse()\n\t\t\t\tconst xBackgroundPositions = styles.backgroundPositionX.split(/\\s*,\\s*/g)\n\t\t\t\tconst yBackgroundPositions = styles.backgroundPositionY.split(/\\s*,\\s*/g)\n\t\t\t\tconst backgroundRepeats = styles.backgroundRepeat.split(/\\s*,\\s*/g)\n\t\t\t\tfor (const [index, backgroundNode] of backgrounds.entries()) {\n\t\t\t\t\tconst backgroundPositionX = parseCSSLength(xBackgroundPositions[index]!, bounds.width) ?? 0\n\t\t\t\t\tconst backgroundPositionY = parseCSSLength(yBackgroundPositions[index]!, bounds.height) ?? 0\n\t\t\t\t\tconst backgroundRepeat = backgroundRepeats[index]\n\t\t\t\t\tif (backgroundNode.value === 'url' && backgroundNode.nodes[0]) {\n\t\t\t\t\t\tconst urlArgument = backgroundNode.nodes[0]\n\t\t\t\t\t\tconst image = context.svgDocument.createElementNS(svgNamespace, 'image')\n\t\t\t\t\t\timage.id = context.getUniqueId('background-image') // read by inlineResources()\n\t\t\t\t\t\tconst [cssWidth = 'auto', cssHeight = 'auto'] = styles.backgroundSize.split(' ')\n\t\t\t\t\t\tconst backgroundWidth = parseCSSLength(cssWidth, bounds.width) ?? bounds.width\n\t\t\t\t\t\tconst backgroundHeight = parseCSSLength(cssHeight, bounds.height) ?? bounds.height\n\t\t\t\t\t\timage.setAttribute('width', backgroundWidth.toString())\n\t\t\t\t\t\timage.setAttribute('height', backgroundHeight.toString())\n\t\t\t\t\t\tif (cssWidth !== 'auto' && cssHeight !== 'auto') {\n\t\t\t\t\t\t\timage.setAttribute('preserveAspectRatio', 'none')\n\t\t\t\t\t\t} else if (styles.backgroundSize === 'contain') {\n\t\t\t\t\t\t\timage.setAttribute('preserveAspectRatio', 'xMidYMid meet')\n\t\t\t\t\t\t} else if (styles.backgroundSize === 'cover') {\n\t\t\t\t\t\t\timage.setAttribute('preserveAspectRatio', 'xMidYMid slice')\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Technically not correct, because relative URLs should be resolved relative to the stylesheet,\n\t\t\t\t\t\t// not the page. But we have no means to know what stylesheet the style came from\n\t\t\t\t\t\t// (unless we iterate through all rules in all style sheets and find the matching one).\n\t\t\t\t\t\tconst url = new URL(unescapeStringValue(urlArgument.value), window.location.href)\n\t\t\t\t\t\timage.setAttribute('xlink:href', url.href)\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tbackgroundRepeat === 'no-repeat' ||\n\t\t\t\t\t\t\t(backgroundPositionX === 0 &&\n\t\t\t\t\t\t\t\tbackgroundPositionY === 0 &&\n\t\t\t\t\t\t\t\tbackgroundWidth === bounds.width &&\n\t\t\t\t\t\t\t\tbackgroundHeight === bounds.height)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\timage.setAttribute('x', bounds.x.toString())\n\t\t\t\t\t\t\timage.setAttribute('y', bounds.y.toString())\n\t\t\t\t\t\t\tbackgroundAndBordersContainer.append(image)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\timage.setAttribute('x', '0')\n\t\t\t\t\t\t\timage.setAttribute('y', '0')\n\t\t\t\t\t\t\tconst pattern = context.svgDocument.createElementNS(svgNamespace, 'pattern')\n\t\t\t\t\t\t\tpattern.setAttribute('patternUnits', 'userSpaceOnUse')\n\t\t\t\t\t\t\tpattern.setAttribute('patternContentUnits', 'userSpaceOnUse')\n\t\t\t\t\t\t\tpattern.setAttribute('x', (bounds.x + backgroundPositionX).toString())\n\t\t\t\t\t\t\tpattern.setAttribute('y', (bounds.y + backgroundPositionY).toString())\n\t\t\t\t\t\t\tpattern.setAttribute(\n\t\t\t\t\t\t\t\t'width',\n\t\t\t\t\t\t\t\t(backgroundRepeat === 'repeat' || backgroundRepeat === 'repeat-x'\n\t\t\t\t\t\t\t\t\t? backgroundWidth\n\t\t\t\t\t\t\t\t\t: // If background shouldn't repeat on this axis, make the tile as big as the element so the repetition is cut off.\n\t\t\t\t\t\t\t\t\t backgroundWidth + bounds.x + backgroundPositionX\n\t\t\t\t\t\t\t\t).toString()\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tpattern.setAttribute(\n\t\t\t\t\t\t\t\t'height',\n\t\t\t\t\t\t\t\t(backgroundRepeat === 'repeat' || backgroundRepeat === 'repeat-y'\n\t\t\t\t\t\t\t\t\t? backgroundHeight\n\t\t\t\t\t\t\t\t\t: // If background shouldn't repeat on this axis, make the tile as big as the element so the repetition is cut off.\n\t\t\t\t\t\t\t\t\t backgroundHeight + bounds.y + backgroundPositionY\n\t\t\t\t\t\t\t\t).toString()\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tpattern.id = context.getUniqueId('pattern')\n\t\t\t\t\t\t\tpattern.append(image)\n\t\t\t\t\t\t\tbox.before(pattern)\n\t\t\t\t\t\t\tbox.setAttribute('fill', `url(#${pattern.id})`)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (/^(-webkit-)?linear-gradient$/.test(backgroundNode.value)) {\n\t\t\t\t\t\tconst linearGradientCss = cssValueParser.stringify(backgroundNode)\n\t\t\t\t\t\tconst svgLinearGradient = convertLinearGradient(linearGradientCss, context)\n\t\t\t\t\t\tif (backgroundPositionX !== 0 || backgroundPositionY !== 0) {\n\t\t\t\t\t\t\tsvgLinearGradient.setAttribute(\n\t\t\t\t\t\t\t\t'gradientTransform',\n\t\t\t\t\t\t\t\t`translate(${backgroundPositionX}, ${backgroundPositionY})`\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsvgLinearGradient.id = context.getUniqueId('linear-gradient')\n\t\t\t\t\t\tbox.before(svgLinearGradient)\n\t\t\t\t\t\tbox.setAttribute('fill', `url(#${svgLinearGradient.id})`)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!hasUniformBorder(styles)) {\n\t\t\t// Draw lines for each border\n\t\t\tfor (const borderLine of createBorders(styles, bounds, context)) {\n\t\t\t\tbackgroundAndBordersContainer.append(borderLine)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction createBox(bounds: DOMRectReadOnly, context: Pick<TraversalContext, 'svgDocument'>): SVGRectElement {\n\tconst box = context.svgDocument.createElementNS(svgNamespace, 'rect')\n\n\t// TODO consider rotation\n\tbox.setAttribute('width', bounds.width.toString())\n\tbox.setAttribute('height', bounds.height.toString())\n\tbox.setAttribute('x', bounds.x.toString())\n\tbox.setAttribute('y', bounds.y.toString())\n\n\treturn box\n}\n\nfunction createBackgroundAndBorderBox(\n\tbounds: DOMRectReadOnly,\n\tstyles: CSSStyleDeclaration,\n\tcontext: Pick<TraversalContext, 'svgDocument'>\n): SVGRectElement {\n\tconst background = createBox(bounds, context)\n\n\t// TODO handle background image and other properties\n\tif (styles.backgroundColor) {\n\t\tbackground.setAttribute('fill', styles.backgroundColor)\n\t}\n\n\tif (hasUniformBorder(styles)) {\n\t\t// Uniform border, use stroke\n\t\t// Cannot use borderColor/borderWidth directly as in Firefox those are empty strings.\n\t\t// Need to get the border property from some specific side (they are all the same in this condition).\n\t\t// https://stackoverflow.com/questions/41696063/getcomputedstyle-returns-empty-strings-on-ff-when-instead-crome-returns-a-comp\n\t\tbackground.setAttribute('stroke', styles.borderTopColor)\n\t\tbackground.setAttribute('stroke-width', styles.borderTopWidth)\n\t\tif (styles.borderTopStyle === 'dashed') {\n\t\t\t// > Displays a series of short square-ended dashes or line segments.\n\t\t\t// > The exact size and length of the segments are not defined by the specification and are implementation-specific.\n\t\t\tbackground.setAttribute('stroke-dasharray', '1')\n\t\t}\n\t}\n\n\t// Set border radius\n\t// Approximation, always assumes uniform border-radius by using the top-left horizontal radius and the top-left vertical radius for all corners.\n\t// TODO support irregular border radii on all corners by drawing border as a <path>.\n\tconst overlappingCurvesFactor = calculateOverlappingCurvesFactor(styles, bounds)\n\tconst radiusX = getBorderRadiiForSide('top', styles, bounds)[0] * overlappingCurvesFactor\n\tconst radiusY = getBorderRadiiForSide('left', styles, bounds)[0] * overlappingCurvesFactor\n\tif (radiusX !== 0) {\n\t\tbackground.setAttribute('rx', radiusX.toString())\n\t}\n\tif (radiusY !== 0) {\n\t\tbackground.setAttribute('ry', radiusY.toString())\n\t}\n\n\treturn background\n}\n\nfunction* createBorders(\n\tstyles: CSSStyleDeclaration,\n\tbounds: DOMRectReadOnly,\n\tcontext: Pick<TraversalContext, 'svgDocument'>\n): Iterable<SVGLineElement> {\n\tfor (const side of ['top', 'bottom', 'right', 'left'] as const) {\n\t\tif (hasBorder(styles, side)) {\n\t\t\tyield createBorder(styles, bounds, side, context)\n\t\t}\n\t}\n}\n\nfunction hasBorder(styles: CSSStyleDeclaration, side: Side): boolean {\n\treturn (\n\t\t!!styles.getPropertyValue(`border-${side}-color`) &&\n\t\t!isTransparent(styles.getPropertyValue(`border-${side}-color`)) &&\n\t\tstyles.getPropertyValue(`border-${side}-width`) !== '0px'\n\t)\n}\n\nfunction createBorder(\n\tstyles: CSSStyleDeclaration,\n\tbounds: DOMRectReadOnly,\n\tside: Side,\n\tcontext: Pick<TraversalContext, 'svgDocument'>\n): SVGLineElement {\n\t// TODO handle border-radius for non-uniform borders\n\tconst border = context.svgDocument.createElementNS(svgNamespace, 'line')\n\tborder.setAttribute('stroke-linecap', 'square')\n\tconst color = styles.getPropertyValue(`border-${side}-color`)\n\tborder.setAttribute('stroke', color)\n\tborder.setAttribute('stroke-width', styles.getPropertyValue(`border-${side}-width`))\n\n\t// Handle inset/outset borders\n\tconst borderStyle = styles.getPropertyValue(`border-${side}-style`)\n\tif (\n\t\t(borderStyle === 'inset' && (side === 'top' || side === 'left')) ||\n\t\t(borderStyle === 'outset' && (side === 'right' || side === 'bottom'))\n\t) {\n\t\tconst match = color.match(/rgba?\\((\\d+), (\\d+), (\\d+)(?:, ([\\d.]+))?\\)/)\n\t\tif (!match) {\n\t\t\tthrow new Error(`Unexpected color: ${color}`)\n\t\t}\n\t\tconst components = match.slice(1, 4).map(value => parseInt(value, 10) * 0.3)\n\t\tif (match[4]) {\n\t\t\tcomponents.push(parseFloat(match[4]))\n\t\t}\n\t\t// Low-light border\n\t\t// https://stackoverflow.com/questions/4147940/how-do-browsers-determine-which-exact-colors-to-use-for-border-inset-or-outset\n\t\tborder.setAttribute('stroke', `rgba(${components.join(', ')})`)\n\t}\n\n\tif (side === 'top') {\n\t\tborder.setAttribute('x1', bounds.left.toString())\n\t\tborder.setAttribute('x2', bounds.right.toString())\n\t\tborder.setAttribute('y1', bounds.top.toString())\n\t\tborder.setAttribute('y2', bounds.top.toString())\n\t} else if (side === 'left') {\n\t\tborder.setAttribute('x1', bounds.left.toString())\n\t\tborder.setAttribute('x2', bounds.left.toString())\n\t\tborder.setAttribute('y1', bounds.top.toString())\n\t\tborder.setAttribute('y2', bounds.bottom.toString())\n\t} else if (side === 'right') {\n\t\tborder.setAttribute('x1', bounds.right.toString())\n\t\tborder.setAttribute('x2', bounds.right.toString())\n\t\tborder.setAttribute('y1', bounds.top.toString())\n\t\tborder.setAttribute('y2', bounds.bottom.toString())\n\t} else if (side === 'bottom') {\n\t\tborder.setAttribute('x1', bounds.left.toString())\n\t\tborder.setAttribute('x2', bounds.right.toString())\n\t\tborder.setAttribute('y1', bounds.bottom.toString())\n\t\tborder.setAttribute('y2', bounds.bottom.toString())\n\t}\n\treturn border\n}\n\nfunction createSvgAnchor(element: HTMLAnchorElement, context: Pick<TraversalContext, 'svgDocument'>): SVGAElement {\n\tconst svgAnchor = context.svgDocument.createElementNS(svgNamespace, 'a')\n\tif (element.href && !element.href.startsWith('javascript:')) {\n\t\tsvgAnchor.setAttribute('href', element.href)\n\t}\n\tif (element.rel) {\n\t\tsvgAnchor.setAttribute('rel', element.rel)\n\t}\n\tif (element.target) {\n\t\tsvgAnchor.setAttribute('target', element.target)\n\t}\n\tif (element.download) {\n\t\tsvgAnchor.setAttribute('download', element.download)\n\t}\n\treturn svgAnchor\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradients.d.ts","sourceRoot":"","sources":["../src/gradients.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAyCjD,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,MAAM,EACX,EAAE,WAAW,EAAE,EAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,GACpD,wBAAwB,CAiD1B"}
|
package/lib/gradients.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* eslint-disable id-length */
|
|
2
|
+
import * as gradientParser from 'gradient-parser';
|
|
3
|
+
import { svgNamespace } from './dom.js';
|
|
4
|
+
const positionsForOrientation = (orientation) => {
|
|
5
|
+
const positions = {
|
|
6
|
+
x1: '0%',
|
|
7
|
+
x2: '0%',
|
|
8
|
+
y1: '0%',
|
|
9
|
+
y2: '0%',
|
|
10
|
+
};
|
|
11
|
+
if ((orientation === null || orientation === void 0 ? void 0 : orientation.type) === 'angular') {
|
|
12
|
+
const anglePI = orientation.value * (Math.PI / 180);
|
|
13
|
+
positions.x1 = `${Math.round(50 + Math.sin(anglePI + Math.PI) * 50)}%`;
|
|
14
|
+
positions.y1 = `${Math.round(50 + Math.cos(anglePI) * 50)}%`;
|
|
15
|
+
positions.x2 = `${Math.round(50 + Math.sin(anglePI) * 50)}%`;
|
|
16
|
+
positions.y2 = `${Math.round(50 + Math.cos(anglePI + Math.PI) * 50)}%`;
|
|
17
|
+
}
|
|
18
|
+
else if ((orientation === null || orientation === void 0 ? void 0 : orientation.type) === 'directional') {
|
|
19
|
+
switch (orientation.value) {
|
|
20
|
+
case 'left':
|
|
21
|
+
positions.x1 = '100%';
|
|
22
|
+
break;
|
|
23
|
+
case 'top':
|
|
24
|
+
positions.y1 = '100%';
|
|
25
|
+
break;
|
|
26
|
+
case 'right':
|
|
27
|
+
positions.x2 = '100%';
|
|
28
|
+
break;
|
|
29
|
+
case 'bottom':
|
|
30
|
+
positions.y2 = '100%';
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return positions;
|
|
35
|
+
};
|
|
36
|
+
export function convertLinearGradient(css, { svgDocument }) {
|
|
37
|
+
const { orientation, colorStops } = gradientParser.parse(css)[0];
|
|
38
|
+
const { x1, x2, y1, y2 } = positionsForOrientation(orientation);
|
|
39
|
+
const getColorStops = (colorStop, index) => {
|
|
40
|
+
const offset = `${(index / (colorStops.length - 1)) * 100}%`;
|
|
41
|
+
let stopColor = 'rgb(0,0,0)';
|
|
42
|
+
let stopOpacity = 1;
|
|
43
|
+
switch (colorStop.type) {
|
|
44
|
+
case 'rgb': {
|
|
45
|
+
const [red, green, blue] = colorStop.value;
|
|
46
|
+
stopColor = `rgb(${red},${green},${blue})`;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case 'rgba': {
|
|
50
|
+
const [red, green, blue, alpha] = colorStop.value;
|
|
51
|
+
stopColor = `rgb(${red},${green},${blue})`;
|
|
52
|
+
stopOpacity = alpha;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case 'hex': {
|
|
56
|
+
stopColor = `#${colorStop.value}`;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case 'literal': {
|
|
60
|
+
stopColor = colorStop.value;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const stop = svgDocument.createElementNS(svgNamespace, 'stop');
|
|
65
|
+
stop.setAttribute('offset', offset);
|
|
66
|
+
stop.setAttribute('stop-color', stopColor);
|
|
67
|
+
stop.setAttribute('stop-opacity', stopOpacity.toString());
|
|
68
|
+
return stop;
|
|
69
|
+
};
|
|
70
|
+
const linearGradient = svgDocument.createElementNS(svgNamespace, 'linearGradient');
|
|
71
|
+
linearGradient.setAttribute('x1', x1);
|
|
72
|
+
linearGradient.setAttribute('y1', y1);
|
|
73
|
+
linearGradient.setAttribute('x2', x2);
|
|
74
|
+
linearGradient.setAttribute('y2', y2);
|
|
75
|
+
linearGradient.append(...colorStops.map(getColorStops));
|
|
76
|
+
return linearGradient;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=gradients.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradients.js","sourceRoot":"","sources":["../src/gradients.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable id-length */\nimport * as gradientParser from 'gradient-parser'\n\nimport { svgNamespace } from './dom.js'\nimport { TraversalContext } from './traversal.js'\n\nconst positionsForOrientation = (\n\torientation: gradientParser.Gradient['orientation']\n): Record<'x1' | 'x2' | 'y1' | 'y2', string> => {\n\tconst positions = {\n\t\tx1: '0%',\n\t\tx2: '0%',\n\t\ty1: '0%',\n\t\ty2: '0%',\n\t}\n\n\tif (orientation?.type === 'angular') {\n\t\tconst anglePI = orientation.value * (Math.PI / 180)\n\t\tpositions.x1 = `${Math.round(50 + Math.sin(anglePI + Math.PI) * 50)}%`\n\t\tpositions.y1 = `${Math.round(50 + Math.cos(anglePI) * 50)}%`\n\t\tpositions.x2 = `${Math.round(50 + Math.sin(anglePI) * 50)}%`\n\t\tpositions.y2 = `${Math.round(50 + Math.cos(anglePI + Math.PI) * 50)}%`\n\t} else if (orientation?.type === 'directional') {\n\t\tswitch (orientation.value) {\n\t\t\tcase 'left':\n\t\t\t\tpositions.x1 = '100%'\n\t\t\t\tbreak\n\n\t\t\tcase 'top':\n\t\t\t\tpositions.y1 = '100%'\n\t\t\t\tbreak\n\n\t\t\tcase 'right':\n\t\t\t\tpositions.x2 = '100%'\n\t\t\t\tbreak\n\n\t\t\tcase 'bottom':\n\t\t\t\tpositions.y2 = '100%'\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\treturn positions\n}\n\nexport function convertLinearGradient(\n\tcss: string,\n\t{ svgDocument }: Pick<TraversalContext, 'svgDocument'>\n): SVGLinearGradientElement {\n\tconst { orientation, colorStops } = gradientParser.parse(css)[0]!\n\tconst { x1, x2, y1, y2 } = positionsForOrientation(orientation)\n\n\tconst getColorStops = (colorStop: gradientParser.ColorStop, index: number): SVGStopElement => {\n\t\tconst offset = `${(index / (colorStops.length - 1)) * 100}%`\n\t\tlet stopColor = 'rgb(0,0,0)'\n\t\tlet stopOpacity = 1\n\n\t\tswitch (colorStop.type) {\n\t\t\tcase 'rgb': {\n\t\t\t\tconst [red, green, blue] = colorStop.value\n\t\t\t\tstopColor = `rgb(${red},${green},${blue})`\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'rgba': {\n\t\t\t\tconst [red, green, blue, alpha] = colorStop.value\n\t\t\t\tstopColor = `rgb(${red},${green},${blue})`\n\t\t\t\tstopOpacity = alpha\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'hex': {\n\t\t\t\tstopColor = `#${colorStop.value}`\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'literal': {\n\t\t\t\tstopColor = colorStop.value\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tconst stop = svgDocument.createElementNS(svgNamespace, 'stop')\n\t\tstop.setAttribute('offset', offset)\n\t\tstop.setAttribute('stop-color', stopColor)\n\t\tstop.setAttribute('stop-opacity', stopOpacity.toString())\n\t\treturn stop\n\t}\n\n\tconst linearGradient = svgDocument.createElementNS(svgNamespace, 'linearGradient')\n\tlinearGradient.setAttribute('x1', x1)\n\tlinearGradient.setAttribute('y1', y1)\n\tlinearGradient.setAttribute('x2', x2)\n\tlinearGradient.setAttribute('y2', y2)\n\tlinearGradient.append(...colorStops.map(getColorStops))\n\n\treturn linearGradient\n}\n"]}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DomToSvgOptions } from './traversal.js';
|
|
2
|
+
export { DomToSvgOptions };
|
|
3
|
+
export declare function documentToSVG(document: Document, options?: DomToSvgOptions): XMLDocument;
|
|
4
|
+
export declare function elementToSVG(element: Element, options?: DomToSvgOptions): XMLDocument;
|
|
5
|
+
export { inlineResources } from './inline.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAY,MAAM,gBAAgB,CAAA;AAG1D,OAAO,EAAE,eAAe,EAAE,CAAA;AAE1B,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,WAAW,CAExF;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,WAAW,CAuErF;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
|