html2canvas-pro 2.5.4 → 2.6.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.
@@ -22,7 +22,8 @@ export interface ValidatorConfig {
22
22
  */
23
23
  allowedProxyDomains?: string[];
24
24
  /**
25
- * Allow localhost/127.0.0.1 as proxy URL. Only set for development or test (e.g. Karma reftests).
25
+ * Allow localhost/127.0.0.1 as proxy URL. Only set for development or test
26
+ * (e.g. the Playwright reftest runner, which proxies through localhost).
26
27
  * @default false
27
28
  */
28
29
  allowLocalhostProxy?: boolean;
@@ -81,6 +82,13 @@ export declare class Validator {
81
82
  * @returns Validation result
82
83
  */
83
84
  validateCspNonce(nonce: string): ValidationResult;
85
+ /**
86
+ * Validate the backgroundColor option
87
+ *
88
+ * @param backgroundColor - CSS color string or null (transparent)
89
+ * @returns Validation result
90
+ */
91
+ validateBackgroundColor(backgroundColor: unknown): ValidationResult;
84
92
  /**
85
93
  * Validate image timeout
86
94
  *
@@ -42,6 +42,13 @@ export declare class DocumentCloner {
42
42
  * the other stylesheet-cloning paths.
43
43
  */
44
44
  private appendDocumentAdoptedStyles;
45
+ /**
46
+ * Add the rules that hide the source ::before / ::after (the clone draws
47
+ * them as surrogate elements) to the clone's <head>. Inside <body> the
48
+ * <style> would be one of its children, and `body > :first-child`,
49
+ * `:nth-child()` and sibling selectors would match the wrong elements.
50
+ */
51
+ private appendPseudoHideStyles;
45
52
  toIFrame(ownerDocument: Document, windowSize: Bounds): Promise<HTMLIFrameElement>;
46
53
  createElementClone<T extends HTMLElement | SVGElement>(node: T): HTMLElement | SVGElement;
47
54
  createCustomElementClone(originalNode: HTMLElement, clonedNode: HTMLElement): HTMLElement;
@@ -2,6 +2,7 @@ import { CSSParsedDeclaration } from '../css/index';
2
2
  import { TextContainer } from './text-container';
3
3
  import { Bounds } from '../css/layout/bounds';
4
4
  import { Context } from '../core/context';
5
+ import { FilterReferences } from './filter-reference';
5
6
  export interface ElementContainerOptions {
6
7
  normalizeDom?: boolean;
7
8
  }
@@ -17,6 +18,11 @@ export declare class ElementContainer {
17
18
  * bounds to leave a matching gap (issue #227).
18
19
  */
19
20
  readonly legendBounds?: Bounds;
21
+ /**
22
+ * Same-document `filter: url(#id)` references, resolved while the cloned
23
+ * DOM is available. The surface compositor renders them in an SVG pass.
24
+ */
25
+ readonly filterReferences?: FilterReferences;
20
26
  createsStackingContext: boolean;
21
27
  createsRealStackingContext: boolean;
22
28
  isListOwner: boolean;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CSS `filter: url(#id)` references for the surface compositor.
3
+ *
4
+ * The referenced <filter> is resolved while the cloned DOM is still available
5
+ * and copied into a detached, self-contained form: its region is converted to
6
+ * user space around the element's border box, and presentation properties a
7
+ * stylesheet may set are inlined. The copy is later serialized into an SVG
8
+ * image together with the composited surface, so it must not depend on the
9
+ * document it came from.
10
+ */
11
+ export interface FilterRegion {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ }
17
+ export interface FilterReference {
18
+ /** Detached copy with a userSpaceOnUse region relative to the border box. */
19
+ readonly element: SVGFilterElement;
20
+ readonly region: FilterRegion;
21
+ /** How far (CSS px) the filter region reaches beyond the border box. */
22
+ readonly outset: number;
23
+ }
24
+ export type FilterReferences = ReadonlyMap<string, FilterReference>;
25
+ /** The `#id` of a same-document url() body (`"#id"`, `'#id'` or `#id`), or null. */
26
+ export declare const parseFilterReference: (body: string) => string | null;
27
+ /**
28
+ * Resolve every same-document url() reference of a computed filter value.
29
+ * References that cannot be expressed in the serialized SVG are left out, so
30
+ * the compositor rejects the chain and the subtree keeps the legacy renderer.
31
+ */
32
+ export declare function resolveFilterReferences(element: Element, filter: string | null, box: {
33
+ width: number;
34
+ height: number;
35
+ }): FilterReferences | undefined;
@@ -64,7 +64,7 @@ export declare const createIFrameContainer: (ownerDocument: Document, bounds: Bo
64
64
  */
65
65
  export declare const stylesheetsReady: (documentClone: Document, logger?: {
66
66
  warn: (msg: string) => void;
67
- }, signal?: AbortSignal) => Promise<void>;
67
+ }, signal?: AbortSignal, timeoutMs?: number) => Promise<void>;
68
68
  /**
69
69
  * Serialise a document type declaration to an HTML string.
70
70
  * @internal – exported for testing only, not part of the public API.
@@ -15,9 +15,9 @@ export declare enum PseudoElementType {
15
15
  }
16
16
  /**
17
17
  * Inject the stylesheet that hides pseudo-element surrogate containers.
18
- * Called on the cloned <body> so the surrogates themselves never render.
18
+ * Added to the cloned <head> so the surrogates themselves never render.
19
19
  */
20
- export declare const createPseudoHideStyles: (body: HTMLElement, cspNonce?: string) => void;
20
+ export declare const createPseudoHideStyles: (parent: Element, cspNonce?: string) => void;
21
21
  /**
22
22
  * Resolves computed `content` of ::before/::after into surrogate DOM nodes.
23
23
  *
@@ -1,12 +1,14 @@
1
+ import { FilterReferences } from '../../dom/filter-reference';
1
2
  export declare class FilterSurfaceError extends Error {
2
3
  }
3
4
  export declare const releaseSurface: (canvas: HTMLCanvasElement) => void;
4
5
  /**
5
6
  * A parsed CSS filter chain. Functions keep their declaration order — CSS
6
7
  * applies them left to right, and the native canvas backend reproduces that
7
- * order exactly. Chains containing functions the backends cannot express
8
- * (url() references, unknown functions) fail parsing and stay on the legacy
9
- * renderer, where ctx.filter receives the full string natively.
8
+ * order exactly. Same-document url() references are kept as their own step
9
+ * and rendered by an SVG pass. Chains containing functions the backends
10
+ * cannot express (external url() references, unknown functions) fail parsing
11
+ * and stay on the legacy renderer, where ctx.filter receives the full string.
10
12
  */
11
13
  export type FilterFunction = {
12
14
  kind: 'blur';
@@ -21,6 +23,9 @@ export type FilterFunction = {
21
23
  kind: 'unitless';
22
24
  name: UnitlessFilterName;
23
25
  value: number;
26
+ } | {
27
+ kind: 'url';
28
+ ref: string;
24
29
  };
25
30
  export type UnitlessFilterName = 'brightness' | 'contrast' | 'grayscale' | 'hue-rotate' | 'invert' | 'opacity' | 'saturate' | 'sepia';
26
31
  export interface ParsedFilter {
@@ -36,8 +41,18 @@ export declare const nativeFilterString: (filter: ParsedFilter, scale: number) =
36
41
  /**
37
42
  * Outset (in CSS pixels) a surface must grow so blur/shadow spillover is not
38
43
  * cropped. Unitless functions never spread beyond the bounds. Consecutive
39
- * blurs compound, so their radii sum.
44
+ * blurs compound, so their radii sum. A url() reference can paint up to its
45
+ * filter region, which may extend beyond the border box.
40
46
  */
41
- export declare function filterOutset(filter: ParsedFilter): number;
47
+ export declare function filterOutset(filter: ParsedFilter, references?: FilterReferences): number;
42
48
  export declare function supportsNativeFilters(owner?: Document): boolean;
43
- export declare function renderFilterSurface(source: HTMLCanvasElement, filter: ParsedFilter, opacity: number, scale: number, signal?: AbortSignal): Promise<HTMLCanvasElement>;
49
+ /** Where url() references resolve, and the border box origin inside the surface (CSS px). */
50
+ export interface FilterSurfaceReferences {
51
+ references?: FilterReferences;
52
+ origin: {
53
+ x: number;
54
+ y: number;
55
+ };
56
+ }
57
+ export declare function renderFilterSurface(source: HTMLCanvasElement, filter: ParsedFilter, opacity: number, scale: number, signal?: AbortSignal, references?: FilterSurfaceReferences): Promise<HTMLCanvasElement>;
58
+ export declare function renderSvgFilterSurface(source: HTMLCanvasElement, filter: ParsedFilter, opacity: number, scale: number, signal?: AbortSignal): Promise<HTMLCanvasElement>;
package/package.json CHANGED
@@ -19,7 +19,7 @@
19
19
  "default": "./dist/html2canvas-pro.esm.js"
20
20
  }
21
21
  },
22
- "version": "2.5.4",
22
+ "version": "2.6.1",
23
23
  "author": {
24
24
  "name": "yorickshan",
25
25
  "email": "yorickshan@gmail.com",
@@ -39,10 +39,10 @@
39
39
  "url": "https://github.com/yorickshan/html2canvas-pro"
40
40
  },
41
41
  "devDependencies": {
42
- "@commitlint/cli": "^21.2.3",
43
- "@commitlint/config-conventional": "^21.2.3",
42
+ "@commitlint/cli": "^21.2.4",
43
+ "@commitlint/config-conventional": "^21.2.4",
44
44
  "@types/express": "^5.0.6",
45
- "@types/node": "^26.6.5",
45
+ "@types/node": "^24.0.0",
46
46
  "@types/pngjs": "^6.0.5",
47
47
  "@types/serve-index": "^1.9.4",
48
48
  "@typescript-eslint/eslint-plugin": "^8.71.2",
@@ -50,7 +50,7 @@
50
50
  "@typescript/native": "npm:typescript@^7.0.2",
51
51
  "@vitest/coverage-v8": "^5.0.4",
52
52
  "axios": "^1.20.0",
53
- "body-parser": "^2.3.0",
53
+ "body-parser": "^2.4.0",
54
54
  "conventional-changelog": "^8.1.3",
55
55
  "conventional-changelog-conventionalcommits": "^10.4.1",
56
56
  "cors": "^2.8.6",
@@ -58,10 +58,10 @@
58
58
  "eslint-config-prettier": "^10.1.8",
59
59
  "eslint-plugin-prettier": "^5.5.6",
60
60
  "express": "^5.3.0",
61
- "express-rate-limit": "^8.7.1",
61
+ "express-rate-limit": "^8.7.2",
62
62
  "glob": "^13.0.6",
63
63
  "husky": "^9.1.7",
64
- "jsdom": "^30.1.2",
64
+ "jsdom": "^30.1.3",
65
65
  "lint-staged": "^17.6.0",
66
66
  "pixelmatch": "^8.0.0",
67
67
  "playwright": "1.64.0",
@@ -91,8 +91,9 @@
91
91
  "build:reftest-result-list": "tsx scripts/create-reftest-result-list.ts",
92
92
  "build:create-reftest-list": "tsx scripts/create-reftest-list.ts tests/reftests/ignore.txt build/reftests.js",
93
93
  "release": "sh scripts/version-upgrade.sh",
94
- "format": "prettier --write \"{src,tests,scripts}/**/*.ts\"",
95
- "lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" \"scripts/**/*.mjs\" --max-warnings 0",
94
+ "format": "prettier --write \"{src,tests,scripts,examples}/**/*.ts\"",
95
+ "lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" \"scripts/**/*.mjs\" \"examples/**/*.ts\" --max-warnings 0",
96
+ "typecheck:examples": "tsc -p tsconfig.examples.json",
96
97
  "test": "pnpm lint && pnpm unittest && pnpm reftests:pw",
97
98
  "unittest": "vitest run",
98
99
  "unittest:coverage": "vitest run --coverage",