@@ -2,12 +2,14 @@ import {Bounds} from '../css/layout/bounds';
22import {
33 isBodyElement ,
44 isCanvasElement ,
5+ isCustomElement ,
56 isElementNode ,
67 isHTMLElementNode ,
78 isIFrameElement ,
89 isImageElement ,
910 isScriptElement ,
1011 isSelectElement ,
12+ isSlotElement ,
1113 isStyleElement ,
1214 isSVGElementNode ,
1315 isTextareaElement ,
@@ -63,7 +65,7 @@ export class DocumentCloner {
6365 throw new Error ( 'Cloned element does not have an owner document' ) ;
6466 }
6567
66- this . documentElement = this . cloneNode ( element . ownerDocument . documentElement ) as HTMLElement ;
68+ this . documentElement = this . cloneNode ( element . ownerDocument . documentElement , false ) as HTMLElement ;
6769 }
6870
6971 toIFrame ( ownerDocument : Document , windowSize : Bounds ) : Promise < HTMLIFrameElement > {
@@ -160,6 +162,17 @@ export class DocumentCloner {
160162 }
161163 }
162164
165+ if ( isCustomElement ( clone ) ) {
166+ return this . createCustomElementClone ( clone ) ;
167+ }
168+
169+ return clone ;
170+ }
171+
172+ createCustomElementClone ( node : HTMLElement ) : HTMLElement {
173+ const clone = document . createElement ( 'html2canvascustomelement' ) ;
174+ copyCSSStyles ( node . style , clone ) ;
175+
163176 return clone ;
164177 }
165178
@@ -231,7 +244,20 @@ export class DocumentCloner {
231244 return clonedCanvas ;
232245 }
233246
234- cloneNode ( node : Node ) : Node {
247+ appendChildNode ( clone : HTMLElement | SVGElement , child : Node , copyStyles : boolean ) : void {
248+ if (
249+ ! isElementNode ( child ) ||
250+ ( ! isScriptElement ( child ) &&
251+ ! child . hasAttribute ( IGNORE_ATTRIBUTE ) &&
252+ ( typeof this . options . ignoreElements !== 'function' || ! this . options . ignoreElements ( child ) ) )
253+ ) {
254+ if ( ! this . options . copyStyles || ! isElementNode ( child ) || ! isStyleElement ( child ) ) {
255+ clone . appendChild ( this . cloneNode ( child , copyStyles ) ) ;
256+ }
257+ }
258+ }
259+
260+ cloneNode ( node : Node , copyStyles : boolean ) : Node {
235261 if ( isTextNode ( node ) ) {
236262 return document . createTextNode ( node . data ) ;
237263 }
@@ -260,16 +286,22 @@ export class DocumentCloner {
260286 const counters = this . counters . parse ( new CSSParsedCounterDeclaration ( this . context , style ) ) ;
261287 const before = this . resolvePseudoContent ( node , clone , styleBefore , PseudoElementType . BEFORE ) ;
262288
263- for ( let child = node . firstChild ; child ; child = child . nextSibling ) {
264- if (
265- ! isElementNode ( child ) ||
266- ( ! isScriptElement ( child ) &&
267- ! child . hasAttribute ( IGNORE_ATTRIBUTE ) &&
268- ( typeof this . options . ignoreElements !== 'function' || ! this . options . ignoreElements ( child ) ) )
269- ) {
270- if ( ! this . options . copyStyles || ! isElementNode ( child ) || ! isStyleElement ( child ) ) {
271- clone . appendChild ( this . cloneNode ( child ) ) ;
289+ if ( isCustomElement ( node ) ) {
290+ copyStyles = true ;
291+ }
292+
293+ for (
294+ let child = node . shadowRoot ? node . shadowRoot . firstChild : node . firstChild ;
295+ child ;
296+ child = child . nextSibling
297+ ) {
298+ if ( isElementNode ( child ) && isSlotElement ( child ) && typeof child . assignedNodes === 'function' ) {
299+ const assignedNodes = child . assignedNodes ( ) as ChildNode [ ] ;
300+ if ( assignedNodes . length ) {
301+ assignedNodes . forEach ( ( assignedNode ) => this . appendChildNode ( clone , assignedNode , copyStyles ) ) ;
272302 }
303+ } else {
304+ this . appendChildNode ( clone , child , copyStyles ) ;
273305 }
274306 }
275307
@@ -284,7 +316,10 @@ export class DocumentCloner {
284316
285317 this . counters . pop ( counters ) ;
286318
287- if ( style && ( this . options . copyStyles || isSVGElementNode ( node ) ) && ! isIFrameElement ( node ) ) {
319+ if (
320+ ( style && ( this . options . copyStyles || isSVGElementNode ( node ) ) && ! isIFrameElement ( node ) ) ||
321+ copyStyles
322+ ) {
288323 copyCSSStyles ( style , clone ) ;
289324 }
290325
0 commit comments