Skip to content

Commit

Permalink
feat: clone-svg rename to embed-svg-use
Browse files Browse the repository at this point in the history
  • Loading branch information
qq15725 committed Sep 10, 2023
1 parent d1bee55 commit 67589ab
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 81 deletions.
6 changes: 0 additions & 6 deletions src/clone-element.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { cloneSvg } from './clone-svg'
import {
isCanvasElement,
isIFrameElement,
isImageElement,
isSVGSVGElementNode,
isVideoElement,
} from './utils'
import { cloneIframe } from './clone-iframe'
Expand Down Expand Up @@ -32,9 +30,5 @@ export function cloneElement<T extends HTMLElement | SVGElement>(
return cloneVideo(node)
}

if (isSVGSVGElementNode(node)) {
return cloneSvg(node, context)
}

return node.cloneNode(false) as T
}
54 changes: 0 additions & 54 deletions src/clone-svg.ts

This file was deleted.

24 changes: 12 additions & 12 deletions src/embed-image-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,43 @@ import { contextFetch } from './fetch'
import type { Context } from './context'

export function embedImageElement<T extends HTMLImageElement | SVGImageElement>(
clone: T,
cloned: T,
context: Context,
): Promise<void>[] {
if (isImageElement(clone)) {
const originalSrc = clone.currentSrc || clone.src
if (isImageElement(cloned)) {
const originalSrc = cloned.currentSrc || cloned.src

if (!isDataUrl(originalSrc)) {
return [
contextFetch(context, {
url: originalSrc,
imageDom: clone,
imageDom: cloned,
requestType: 'image',
responseType: 'dataUrl',
}).then(url => {
if (!url) return
clone.srcset = ''
clone.dataset.originalSrc = originalSrc
clone.src = url || ''
cloned.srcset = ''
cloned.dataset.originalSrc = originalSrc
cloned.src = url || ''
}),
]
}

if (IN_SAFARI || IN_FIREFOX) {
context.drawImageCount++
}
} else if (isSVGElementNode(clone) && !isDataUrl(clone.href.baseVal)) {
const originalSrc = clone.href.baseVal
} else if (isSVGElementNode(cloned) && !isDataUrl(cloned.href.baseVal)) {
const originalSrc = cloned.href.baseVal
return [
contextFetch(context, {
url: originalSrc,
imageDom: clone,
imageDom: cloned,
requestType: 'image',
responseType: 'dataUrl',
}).then(url => {
if (!url) return
clone.dataset.originalSrc = originalSrc
clone.href.baseVal = url || ''
cloned.dataset.originalSrc = originalSrc
cloned.href.baseVal = url || ''
}),
]
}
Expand Down
20 changes: 13 additions & 7 deletions src/embed-node.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import { embedImageElement } from './embed-image-element'
import { embedCssStyleImage } from './embed-css-style-image'
import { embedSvgUse } from './embed-svg-use'
import {
isElementNode,
isHTMLElementNode,
isImageElement,
isSVGImageElementNode,
isSVGUseElementNode,
} from './utils'
import type { Context } from './context'

export function embedNode<T extends Node>(clone: T, context: Context) {
export function embedNode<T extends Node>(cloned: T, context: Context) {
const { tasks } = context

if (isElementNode(clone)) {
if (isImageElement(clone) || isSVGImageElementNode(clone)) {
tasks.push(...embedImageElement(clone, context))
if (isElementNode(cloned)) {
if (isImageElement(cloned) || isSVGImageElementNode(cloned)) {
tasks.push(...embedImageElement(cloned, context))
}

if (isSVGUseElementNode(cloned)) {
tasks.push(...embedSvgUse(cloned, context))
}
}

if (isHTMLElementNode(clone)) {
tasks.push(...embedCssStyleImage(clone.style, context))
if (isHTMLElementNode(cloned)) {
tasks.push(...embedCssStyleImage(cloned.style, context))
}

clone.childNodes.forEach(child => {
cloned.childNodes.forEach(child => {
embedNode(child, context)
})
}
53 changes: 53 additions & 0 deletions src/embed-svg-use.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { cloneNode } from './clone-node'
import { contextFetch } from './fetch'
import type { Context } from './context'

export function embedSvgUse<T extends SVGUseElement>(
cloned: T,
context: Context,
): Promise<void>[] {
const { ownerDocument, svgDefsElement } = context

const href = cloned.getAttribute('href') // check href first as this is preferred and will be used if both are set
?? cloned.getAttribute('xlink:href')

if (!href) return [] // skip blank hrefs

const [svgUrl, id] = href.split('#')

if (id) {
const query = `#${ id }`
const definition = ownerDocument?.querySelector(`svg ${ query }`)

if (svgUrl) {
// change the href attribute to use a local symbol on this cloned use-node
cloned.setAttribute('href', query)
// No need to set xlink:href since this is ignored when href is set
}

if (svgDefsElement?.querySelector(query)) return [] // already exists in defs

if (definition) { // found local embedded definition
return [
cloneNode(definition, context)
.then(clonedChildNode => {
if (!svgDefsElement?.querySelector(query)) {
svgDefsElement?.appendChild(clonedChildNode)
}
}),
]
} else if (svgUrl) { // no local definition but found an url
// try to fetch the svg and append it to the svgDefsElement
return [
contextFetch(context, {
url: svgUrl,
responseType: 'text',
}).then(svgData => {
svgDefsElement?.insertAdjacentHTML('beforeend', svgData)
}),
]
}
}

return []
}
4 changes: 2 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export const isCSSImportRule = (rule: CSSRule): rule is CSSImportRule => rule.co
// Element
export const isElementNode = (node: Node): node is Element => node.nodeType === 1 // Node.ELEMENT_NODE
export const isSVGElementNode = (node: Element): node is SVGElement => typeof (node as SVGElement).className === 'object'
export const isSVGSVGElementNode = (node: Element): node is SVGSVGElement => isSVGElementNode(node) && node.tagName === 'svg'
export const isSVGImageElementNode = (node: Element): node is SVGImageElement => isSVGElementNode(node) && node.tagName === 'image'
export const isSVGImageElementNode = (node: Element): node is SVGImageElement => node.tagName === 'image'
export const isSVGUseElementNode = (node: Element): node is SVGUseElement => node.tagName === 'use'
export const isHTMLElementNode = (node: Node): node is HTMLElement => isElementNode(node) && typeof (node as HTMLElement).style !== 'undefined' && !isSVGElementNode(node)
export const isCommentNode = (node: Node): node is Text => node.nodeType === 8 // Node.COMMENT_NODE
export const isTextNode = (node: Node): node is Text => node.nodeType === 3 // Node.TEXT_NODE
Expand Down

1 comment on commit 67589ab

@vercel
Copy link

@vercel vercel bot commented on 67589ab Sep 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

modern-screenshot – ./

modern-screenshot.vercel.app
modern-screenshot-git-main-qq15725.vercel.app
modern-screenshot-qq15725.vercel.app

Please sign in to comment.