@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/text.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"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","sourcesContent":["import { isVisible } from './css.js'\nimport { svgNamespace } from './dom.js'\nimport { TraversalContext } from './traversal.js'\nimport { doRectanglesIntersect, assert } from './util.js'\n\nexport function handleTextNode(textNode: Text, context: TraversalContext): void {\n\tif (!textNode.ownerDocument.defaultView) {\n\t\tthrow new Error(\"Element's ownerDocument has no defaultView\")\n\t}\n\tconst window = textNode.ownerDocument.defaultView\n\tconst parentElement = textNode.parentElement!\n\tconst styles = window.getComputedStyle(parentElement)\n\tif (!isVisible(styles)) {\n\t\treturn\n\t}\n\n\tconst selection = window.getSelection()\n\tassert(\n\t\tselection,\n\t\t'Could not obtain selection from window. Selection is needed for detecting whitespace collapsing in text.'\n\t)\n\n\tconst svgTextElement = context.svgDocument.createElementNS(svgNamespace, 'text')\n\n\t// Copy text styles\n\t// https://css-tricks.com/svg-properties-and-css\n\tcopyTextStyles(styles, svgTextElement)\n\n\tconst tabSize = parseInt(styles.tabSize, 10)\n\n\t// Make sure the y attribute is the bottom of the box, not the baseline\n\tsvgTextElement.setAttribute('dominant-baseline', 'text-after-edge')\n\n\tconst lineRange = textNode.ownerDocument.createRange()\n\tlineRange.setStart(textNode, 0)\n\tlineRange.setEnd(textNode, 0)\n\twhile (true) {\n\t\tconst addTextSpanForLineRange = (): void => {\n\t\t\tif (lineRange.collapsed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst lineRectangle = lineRange.getClientRects()[0]!\n\t\t\tif (!doRectanglesIntersect(lineRectangle, context.options.captureArea)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst textSpan = context.svgDocument.createElementNS(svgNamespace, 'tspan')\n\t\t\ttextSpan.setAttribute('xml:space', 'preserve')\n\n\t\t\t// lineRange.toString() returns the text including whitespace.\n\t\t\t// by adding the range to a Selection, then getting the text from that selection,\n\t\t\t// we can let the DOM handle whitespace collapsing the same way as innerText (but for a Range).\n\t\t\t// For this to work, the parent element must not forbid user selection.\n\t\t\tconst previousUserSelect = parentElement.style.userSelect\n\t\t\tparentElement.style.userSelect = 'all'\n\t\t\ttry {\n\t\t\t\tselection.removeAllRanges()\n\t\t\t\tselection.addRange(lineRange)\n\t\t\t\ttextSpan.textContent = selection\n\t\t\t\t\t.toString()\n\t\t\t\t\t// SVG does not support tabs in text. Tabs get rendered as one space character. Convert the\n\t\t\t\t\t// tabs to spaces according to tab-size instead.\n\t\t\t\t\t// Ideally we would keep the tab and create offset tspans.\n\t\t\t\t\t.replace(/\\t/g, ' '.repeat(tabSize))\n\t\t\t} finally {\n\t\t\t\tparentElement.style.userSelect = previousUserSelect\n\t\t\t\tselection.removeAllRanges()\n\t\t\t}\n\n\t\t\ttextSpan.setAttribute('x', lineRectangle.x.toString())\n\t\t\ttextSpan.setAttribute('y', lineRectangle.bottom.toString()) // intentionally bottom because of dominant-baseline setting\n\n\t\t\tconst textContent = textSpan.textContent || ''\n\t\t\tconst textLength = textContent.length\n\t\t\tconsole.log('textLength', textLength)\n\t\t\tif (textLength > 0) {\n\t\t\t\t// Calculate an appropriate font size based on available width\n\t\t\t\t// This is a simple approach - you may need to adjust the divisor based on your specific needs\n\t\t\t\tconst calculatedFontSize = Math.max(8, Math.min(20, lineRectangle.width / (textLength * 0.6)))\n\t\t\t\tconsole.log('calculatedFontSize', calculatedFontSize)\n\t\t\t\ttextSpan.setAttribute('font-size', `${calculatedFontSize}px`)\n\t\t\t}\n\t\t\ttextSpan.setAttribute('textLength', lineRectangle.width.toString())\n\t\t\ttextSpan.setAttribute('lengthAdjust', 'spacingAndGlyphs')\n\t\t\tconst originalFontSize = styles.fontSize\n\t\t\ttextSpan.setAttribute('data-original-font-size', originalFontSize)\n\n\t\t\tsvgTextElement.append(textSpan)\n\t\t}\n\t\ttry {\n\t\t\tlineRange.setEnd(textNode, lineRange.endOffset + 1)\n\t\t} catch (error) {\n\t\t\tif ((error as DOMException).code === DOMException.INDEX_SIZE_ERR) {\n\t\t\t\t// Reached the end\n\t\t\t\taddTextSpanForLineRange()\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t\t// getClientRects() returns one rectangle for each line of a text node.\n\t\tconst lineRectangles = lineRange.getClientRects()\n\t\t// If no lines\n\t\tif (!lineRectangles[0]) {\n\t\t\t// Pure whitespace text nodes are collapsed and not rendered.\n\t\t\treturn\n\t\t}\n\t\t// If two (unique) lines\n\t\t// For some reason, Chrome returns 2 identical DOMRects for text with text-overflow: ellipsis.\n\t\tif (lineRectangles[1] && lineRectangles[0].top !== lineRectangles[1].top) {\n\t\t\t// Crossed a line break.\n\t\t\t// Go back one character to select exactly the previous line.\n\t\t\tlineRange.setEnd(textNode, lineRange.endOffset - 1)\n\t\t\t// Add <tspan> for exactly that line\n\t\t\taddTextSpanForLineRange()\n\t\t\t// Start on the next line.\n\t\t\tlineRange.setStart(textNode, lineRange.endOffset)\n\t\t}\n\t}\n\n\tcontext.currentSvgParent.append(svgTextElement)\n}\n\nexport const textAttributes = new Set([\n\t'color',\n\t'dominant-baseline',\n\t'font-family',\n\t'font-size',\n\t'font-size-adjust',\n\t'font-stretch',\n\t'font-style',\n\t'font-variant',\n\t'font-weight',\n\t'direction',\n\t'letter-spacing',\n\t'text-decoration',\n\t'text-anchor',\n\t'text-decoration',\n\t'text-rendering',\n\t'unicode-bidi',\n\t'word-spacing',\n\t'writing-mode',\n\t'user-select',\n] as const)\nexport function copyTextStyles(styles: CSSStyleDeclaration, svgElement: SVGElement): void {\n\tfor (const textProperty of textAttributes) {\n\t\tconst value = styles.getPropertyValue(textProperty)\n\t\tif (value) {\n\t\t\tsvgElement.setAttribute(textProperty, value)\n\t\t}\n\t}\n\t// tspan uses fill, CSS uses color\n\tsvgElement.setAttribute('fill', styles.color)\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { StackingLayers } from './stacking.js';
|
|
2
|
+
export interface DomToSvgOptions {
|
|
3
|
+
/**
|
|
4
|
+
* To visual area to contrain the SVG too.
|
|
5
|
+
* Elements that do not intersect the capture area are not included in the SVG.
|
|
6
|
+
*/
|
|
7
|
+
captureArea?: DOMRectReadOnly;
|
|
8
|
+
/**
|
|
9
|
+
* Whether to include `<a>` tags in the SVG so links are still interactive.
|
|
10
|
+
*
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
keepLinks?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface TraversalContext {
|
|
16
|
+
readonly svgDocument: XMLDocument;
|
|
17
|
+
readonly currentSvgParent: SVGElement;
|
|
18
|
+
readonly parentStackingLayer: SVGGElement;
|
|
19
|
+
readonly stackingLayers: StackingLayers;
|
|
20
|
+
/**
|
|
21
|
+
* Masks for ancestor elements (that are `overflow: hidden`) affecting the current element, from closest to furthest.
|
|
22
|
+
*/
|
|
23
|
+
readonly ancestorMasks: {
|
|
24
|
+
mask: SVGMaskElement;
|
|
25
|
+
forElement: Element;
|
|
26
|
+
}[];
|
|
27
|
+
readonly labels: Map<HTMLLabelElement, string>;
|
|
28
|
+
readonly getUniqueId: (prefix: string) => string;
|
|
29
|
+
readonly options: Required<DomToSvgOptions>;
|
|
30
|
+
}
|
|
31
|
+
export declare function walkNode(node: Node, context: TraversalContext): void;
|
|
32
|
+
//# sourceMappingURL=traversal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traversal.d.ts","sourceRoot":"","sources":["../src/traversal.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAG9C,MAAM,WAAW,eAAe;IAC/B;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAA;IAE7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,gBAAgB,EAAE,UAAU,CAAA;IACrC,QAAQ,CAAC,mBAAmB,EAAE,WAAW,CAAA;IACzC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;IAEvC;;OAEG;IACH,QAAQ,CAAC,aAAa,EAAE;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;IAEvE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAA;IAC9C,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;IAChD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAA;CAC3C;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAMpE"}
|
package/lib/traversal.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { isElement, isTextNode } from './dom.js';
|
|
2
|
+
import { handleElement } from './element.js';
|
|
3
|
+
import { handleTextNode } from './text.js';
|
|
4
|
+
export function walkNode(node, context) {
|
|
5
|
+
if (isElement(node)) {
|
|
6
|
+
handleElement(node, context);
|
|
7
|
+
}
|
|
8
|
+
else if (isTextNode(node)) {
|
|
9
|
+
handleTextNode(node, context);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=traversal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traversal.js","sourceRoot":"","sources":["../src/traversal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAiC1C,MAAM,UAAU,QAAQ,CAAC,IAAU,EAAE,OAAyB;IAC7D,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE;QACpB,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;KAC5B;SAAM,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE;QAC5B,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;KAC7B;AACF,CAAC","sourcesContent":["import { isElement, isTextNode } from './dom.js'\nimport { handleElement } from './element.js'\nimport { StackingLayers } from './stacking.js'\nimport { handleTextNode } from './text.js'\n\nexport interface DomToSvgOptions {\n\t/**\n\t * To visual area to contrain the SVG too.\n\t * Elements that do not intersect the capture area are not included in the SVG.\n\t */\n\tcaptureArea?: DOMRectReadOnly\n\n\t/**\n\t * Whether to include `<a>` tags in the SVG so links are still interactive.\n\t *\n\t * @default true\n\t */\n\tkeepLinks?: boolean\n}\n\nexport interface TraversalContext {\n\treadonly svgDocument: XMLDocument\n\treadonly currentSvgParent: SVGElement\n\treadonly parentStackingLayer: SVGGElement\n\treadonly stackingLayers: StackingLayers\n\n\t/**\n\t * Masks for ancestor elements (that are `overflow: hidden`) affecting the current element, from closest to furthest.\n\t */\n\treadonly ancestorMasks: { mask: SVGMaskElement; forElement: Element }[]\n\n\treadonly labels: Map<HTMLLabelElement, string>\n\treadonly getUniqueId: (prefix: string) => string\n\treadonly options: Required<DomToSvgOptions>\n}\n\nexport function walkNode(node: Node, context: TraversalContext): void {\n\tif (isElement(node)) {\n\t\thandleElement(node, context)\n\t} else if (isTextNode(node)) {\n\t\thandleTextNode(node, context)\n\t}\n}\n"]}
|
package/lib/util.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const createIdGenerator: () => (prefix: string) => string;
|
|
2
|
+
export declare const isDefined: <T>(value: T) => value is NonNullable<T>;
|
|
3
|
+
/**
|
|
4
|
+
* Check if two rectangles (e.g. an element and the capture area) intersect.
|
|
5
|
+
*/
|
|
6
|
+
export declare const doRectanglesIntersect: (a: DOMRectReadOnly, b: DOMRectReadOnly) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Calculates the length of the diagonale of a given rectangle.
|
|
9
|
+
*/
|
|
10
|
+
export declare function diagonale(box: DOMRectReadOnly): number;
|
|
11
|
+
export declare function withTimeout<T>(timeout: number, message: string, func: () => Promise<T>): Promise<T>;
|
|
12
|
+
/**
|
|
13
|
+
* Type guard to check if an object is a specific member of a tagged union type.
|
|
14
|
+
*
|
|
15
|
+
* @param key The key to check
|
|
16
|
+
* @param value The value the key has to be.
|
|
17
|
+
*/
|
|
18
|
+
export declare const isTaggedUnionMember: <T extends object, K extends keyof T, V extends T[K]>(key: K, value: V) => (object: T) => object is T & Record<K, V>;
|
|
19
|
+
export declare function assert(condition: any, message: string): asserts condition;
|
|
20
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,iBAAiB,MAAM,KAAK,MAOzD,CAAA;AAED,eAAO,MAAM,SAAS,0CAAkF,CAAA;AAExG;;GAEG;AACH,eAAO,MAAM,qBAAqB,MAAO,eAAe,KAAK,eAAe,KAAG,OAO7E,CAAA;AAEF;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAEtD;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAKnG;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,sHAEsB,CAAA;AAEtD,wBAAgB,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAIzE"}
|
package/lib/util.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const createIdGenerator = () => {
|
|
2
|
+
const nextCounts = new Map();
|
|
3
|
+
return prefix => {
|
|
4
|
+
var _a;
|
|
5
|
+
const count = (_a = nextCounts.get(prefix)) !== null && _a !== void 0 ? _a : 1;
|
|
6
|
+
nextCounts.set(prefix, count + 1);
|
|
7
|
+
return `${prefix}${count}`;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export const isDefined = (value) => value !== null && value !== undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Check if two rectangles (e.g. an element and the capture area) intersect.
|
|
13
|
+
*/
|
|
14
|
+
export const doRectanglesIntersect = (a, b) => !(a.bottom < b.top || // A is above B
|
|
15
|
+
a.top > b.bottom || // A is below B
|
|
16
|
+
a.right < b.left || // A is left of B
|
|
17
|
+
// A is right of B
|
|
18
|
+
a.left > b.right);
|
|
19
|
+
/**
|
|
20
|
+
* Calculates the length of the diagonale of a given rectangle.
|
|
21
|
+
*/
|
|
22
|
+
export function diagonale(box) {
|
|
23
|
+
return Math.sqrt(box.width ** 2 + box.height ** 2);
|
|
24
|
+
}
|
|
25
|
+
export function withTimeout(timeout, message, func) {
|
|
26
|
+
return Promise.race([
|
|
27
|
+
func(),
|
|
28
|
+
new Promise((resolve, reject) => setTimeout(() => reject(new Error(message)), timeout)),
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Type guard to check if an object is a specific member of a tagged union type.
|
|
33
|
+
*
|
|
34
|
+
* @param key The key to check
|
|
35
|
+
* @param value The value the key has to be.
|
|
36
|
+
*/
|
|
37
|
+
export const isTaggedUnionMember = (key, value) => (object) => object[key] === value;
|
|
38
|
+
export function assert(condition, message) {
|
|
39
|
+
if (!condition) {
|
|
40
|
+
throw new Error(message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=util.js.map
|
package/lib/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAiC,EAAE;IACnE,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC5C,OAAO,MAAM,CAAC,EAAE;;QACf,MAAM,KAAK,GAAG,MAAA,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,mCAAI,CAAC,CAAA;QACzC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;QACjC,OAAO,GAAG,MAAM,GAAG,KAAK,EAAE,CAAA;IAC3B,CAAC,CAAA;AACF,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAI,KAAQ,EAA2B,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAA;AAExG;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAkB,EAAE,CAAkB,EAAW,EAAE,CACxF,CAAC,CACA,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,eAAe;IACnC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,IAAI,eAAe;IACnC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,IAAI,iBAAiB;IACrC,kBAAkB;IAClB,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAChB,CAAA;AAEF;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAoB;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,WAAW,CAAI,OAAe,EAAE,OAAe,EAAE,IAAsB;IACtF,OAAO,OAAO,CAAC,IAAI,CAAC;QACnB,IAAI,EAAE;QACN,IAAI,OAAO,CAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;KAC9F,CAAC,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAsD,GAAM,EAAE,KAAQ,EAAE,EAAE,CAAC,CAC7G,MAAS,EACoB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAA;AAEtD,MAAM,UAAU,MAAM,CAAC,SAAc,EAAE,OAAe;IACrD,IAAI,CAAC,SAAS,EAAE;QACf,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;KACxB;AACF,CAAC","sourcesContent":["export const createIdGenerator = (): ((prefix: string) => string) => {\n\tconst nextCounts = new Map<string, number>()\n\treturn prefix => {\n\t\tconst count = nextCounts.get(prefix) ?? 1\n\t\tnextCounts.set(prefix, count + 1)\n\t\treturn `${prefix}${count}`\n\t}\n}\n\nexport const isDefined = <T>(value: T): value is NonNullable<T> => value !== null && value !== undefined\n\n/**\n * Check if two rectangles (e.g. an element and the capture area) intersect.\n */\nexport const doRectanglesIntersect = (a: DOMRectReadOnly, b: DOMRectReadOnly): boolean =>\n\t!(\n\t\ta.bottom < b.top || // A is above B\n\t\ta.top > b.bottom || // A is below B\n\t\ta.right < b.left || // A is left of B\n\t\t// A is right of B\n\t\ta.left > b.right\n\t)\n\n/**\n * Calculates the length of the diagonale of a given rectangle.\n */\nexport function diagonale(box: DOMRectReadOnly): number {\n\treturn Math.sqrt(box.width ** 2 + box.height ** 2)\n}\n\nexport function withTimeout<T>(timeout: number, message: string, func: () => Promise<T>): Promise<T> {\n\treturn Promise.race([\n\t\tfunc(),\n\t\tnew Promise<never>((resolve, reject) => setTimeout(() => reject(new Error(message)), timeout)),\n\t])\n}\n\n/**\n * Type guard to check if an object is a specific member of a tagged union type.\n *\n * @param key The key to check\n * @param value The value the key has to be.\n */\nexport const isTaggedUnionMember = <T extends object, K extends keyof T, V extends T[K]>(key: K, value: V) => (\n\tobject: T\n): object is T & Record<K, V> => object[key] === value\n\nexport function assert(condition: any, message: string): asserts condition {\n\tif (!condition) {\n\t\tthrow new Error(message)\n\t}\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eturnity/dom_to_svg",
|
|
3
|
+
"author": "Eturnity Team",
|
|
4
|
+
"version": "8.10.1",
|
|
5
|
+
"description": "Take SVG screenshots of DOM elements",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"lib"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/felixfbecker/dom-to-svg"
|
|
15
|
+
},
|
|
16
|
+
"browserslist": [
|
|
17
|
+
"last 2 Chrome versions",
|
|
18
|
+
"last 2 Firefox versions"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"svg",
|
|
22
|
+
"dom",
|
|
23
|
+
"screenshot",
|
|
24
|
+
"snapshot",
|
|
25
|
+
"document",
|
|
26
|
+
"element",
|
|
27
|
+
"image"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p .",
|
|
31
|
+
"watch": "tsc -p . -w",
|
|
32
|
+
"eslint": "eslint 'src/**/*.ts'",
|
|
33
|
+
"prettier": "prettier --check '**/*.{yml,ts,json}'",
|
|
34
|
+
"get-fixture": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node src/test/get-fixture.ts",
|
|
35
|
+
"test": "mocha src/test/test.ts",
|
|
36
|
+
"semantic-release": "semantic-release"
|
|
37
|
+
},
|
|
38
|
+
"mocha": {
|
|
39
|
+
"timeout": 150000,
|
|
40
|
+
"exit": true,
|
|
41
|
+
"enableSourceMaps": true,
|
|
42
|
+
"watchFiles": [
|
|
43
|
+
"lib/**/*.js"
|
|
44
|
+
],
|
|
45
|
+
"loader": "ts-node/esm"
|
|
46
|
+
},
|
|
47
|
+
"commitlint": {
|
|
48
|
+
"extends": [
|
|
49
|
+
"@commitlint/config-conventional"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"release": {
|
|
53
|
+
"branches": [
|
|
54
|
+
"main"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"husky": {
|
|
58
|
+
"hooks": {
|
|
59
|
+
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@commitlint/cli": "^11.0.0",
|
|
65
|
+
"@commitlint/config-conventional": "^11.0.0",
|
|
66
|
+
"@pollyjs/adapter": "^5.0.0",
|
|
67
|
+
"@pollyjs/core": "^5.0.0",
|
|
68
|
+
"@pollyjs/persister-fs": "^5.0.0",
|
|
69
|
+
"@sourcegraph/eslint-config": "^0.24.0",
|
|
70
|
+
"@sourcegraph/prettierrc": "^3.0.3",
|
|
71
|
+
"@types/chai": "^4.2.19",
|
|
72
|
+
"@types/content-type": "^1.1.3",
|
|
73
|
+
"@types/lodash-es": "^4.17.4",
|
|
74
|
+
"@types/mime-types": "^2.1.0",
|
|
75
|
+
"@types/mocha": "^8.2.2",
|
|
76
|
+
"@types/node": "^14.17.4",
|
|
77
|
+
"@types/parcel-bundler": "^1.12.3",
|
|
78
|
+
"@types/pixelmatch": "^5.2.3",
|
|
79
|
+
"@types/pngjs": "^6.0.0",
|
|
80
|
+
"@types/pollyjs__core": "^4.3.2",
|
|
81
|
+
"@types/pollyjs__persister-fs": "^2.0.1",
|
|
82
|
+
"@types/prettier": "^2.2.3",
|
|
83
|
+
"@types/puppeteer": "^5.4.3",
|
|
84
|
+
"@types/type-is": "^1.6.3",
|
|
85
|
+
"chai": "^4.3.4",
|
|
86
|
+
"chardet": "^1.3.0",
|
|
87
|
+
"content-type": "^1.0.4",
|
|
88
|
+
"delay": "^4.4.0",
|
|
89
|
+
"eslint": "^7.30.0",
|
|
90
|
+
"husky": "^4.3.0",
|
|
91
|
+
"lodash-es": "^4.17.21",
|
|
92
|
+
"mime-types": "^2.1.30",
|
|
93
|
+
"mocha": "^8.3.2",
|
|
94
|
+
"parcel-bundler": "^1.12.5",
|
|
95
|
+
"pixelmatch": "^5.2.1",
|
|
96
|
+
"pngjs": "^6.0.0",
|
|
97
|
+
"prettier": "^2.2.1",
|
|
98
|
+
"puppeteer": "5.4.0",
|
|
99
|
+
"rxjs": "^7.1.0",
|
|
100
|
+
"semantic-release": "^17.2.4",
|
|
101
|
+
"source-map-support": "^0.5.19",
|
|
102
|
+
"tagged-template-noop": "^2.1.1",
|
|
103
|
+
"ts-node": "^9.1.1",
|
|
104
|
+
"typescript": "^4.3.5",
|
|
105
|
+
"xml-formatter": "^2.4.0"
|
|
106
|
+
},
|
|
107
|
+
"dependencies": {
|
|
108
|
+
"gradient-parser": "^1.0.2",
|
|
109
|
+
"postcss": "^8.3.5",
|
|
110
|
+
"postcss-value-parser": "^4.1.0"
|
|
111
|
+
}
|
|
112
|
+
}
|