Skip to content

Commit

Permalink
fix: clone svg symbols (bubkoo#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
bubkoo authored Dec 5, 2022
1 parent 4446626 commit aec6fa1
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/clone-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,53 @@ function decorate<T extends HTMLElement>(nativeNode: T, clonedNode: T): T {
return clonedNode
}

async function ensureSVGSymbols<T extends HTMLElement>(
clone: T,
options: Options,
) {
const uses = clone.querySelectorAll ? clone.querySelectorAll('use') : []
if (uses.length === 0) {
return clone
}

const processedDefs: { [key: string]: HTMLElement } = {}
for (let i = 0; i < uses.length; i++) {
const use = uses[i]
const id = use.getAttribute('xlink:href')
if (id) {
const exist = clone.querySelector(id)
const definition = document.querySelector(id) as HTMLElement
if (!exist && definition && !processedDefs[id]) {
// eslint-disable-next-line no-await-in-loop
processedDefs[id] = (await cloneNode(definition, options, true))!
}
}
}

const nodes = Object.values(processedDefs)
if (nodes.length) {
const ns = 'http://www.w3.org/1999/xhtml'
const svg = document.createElementNS(ns, 'svg')
svg.setAttribute('xmlns', ns)
svg.style.position = 'absolute'
svg.style.width = '0'
svg.style.height = '0'
svg.style.overflow = 'hidden'
svg.style.display = 'none'

const defs = document.createElementNS(ns, 'defs')
svg.appendChild(defs)

for (let i = 0; i < nodes.length; i++) {
defs.appendChild(nodes[i])
}

clone.appendChild(svg)
}

return clone
}

export async function cloneNode<T extends HTMLElement>(
node: T,
options: Options,
Expand All @@ -141,4 +188,5 @@ export async function cloneNode<T extends HTMLElement>(
.then((clonedNode) => cloneSingleNode(clonedNode, options) as Promise<T>)
.then((clonedNode) => cloneChildren(node, clonedNode, options))
.then((clonedNode) => decorate(node, clonedNode))
.then((clonedNode) => ensureSVGSymbols(clonedNode, options))
}
1 change: 1 addition & 0 deletions test/resources/svg-use-tag/image
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAAAwpJREFUeF7tmPGNzFEYRe90QAWUoAN0QAXogApQAR2gAjpAB3RABzpY+TZvZCLDnkl+bkb2vGT+mdzMfXPOvt/3ZncXyUVcZ0NgN0J2ye5sdnSNN3LpQiHn8xegkPNxcbkTIuRekudJXib5lORxkkdJPid5cWbf57/fzlVCBv6bg2/5JMntJWiEjCzXhgT+JuTtOgnv1kmY0zAn40eSG+uEKGRDGX96ZA3sj0nuJJkTMdBHxAj6muTV2oMnZGMZx4SMhPdJbq5ZMbNj3tuvL2uWjJz57XI/ybzn2ojA4SPr4ZoX35O8XidhTsvv69uS8jTJrXWKPmy0n2v/MYdC5hY1j6eBOyfjmIw9sJkjk3+w8iPQtQGBY0N9rrZ3wWc7QwCkUyNEyLM1J2aW7Af69CjkVNogT4TM4J5TM4+zuX3tl0IA4FMjCjmV2D/OHxMyv87ntV9zm5qr7TyyDof3XH3n5dqQwFX/Otmwyo8iBBRCKBUzCinCJlUKIZSKGYUUYZMqhRBKxYxCirBJlUIIpWJGIUXYpEohhFIxo5AibFKlEEKpmFFIETapUgihVMwopAibVCmEUCpmFFKETaoUQigVMwopwiZVCiGUihmFFGGTKoUQSsWMQoqwSZVCCKViRiFF2KRKIYRSMaOQImxSpRBCqZhRSBE2qVIIoVTMKKQIm1QphFAqZhRShE2qFEIoFTMKKcImVQohlIoZhRRhkyqFEErFjEKKsEmVQgilYkYhRdikSiGEUjGjkCJsUqUQQqmYUUgRNqlSCKFUzCikCJtUKYRQKmYUUoRNqhRCKBUzCinCJlUKIZSKGYUUYZMqhRBKxYxCirBJlUIIpWJGIUXYpEohhFIxo5AibFKlEEKpmFFIETapUgihVMwopAibVCmEUCpmFFKETaoUQigVMwopwiZVCiGUihmFFGGTKoUQSsWMQoqwSZVCCKViRiFF2KRKIYRSMaOQImxSpRBCqZhRSBE2qVIIoVTMKKQIm1QphFAqZhRShE2qFEIoFTMKKcImVb+EkLCZDoGfbnm/rNO8R/AAAAAASUVORK5CYII=
28 changes: 28 additions & 0 deletions test/resources/svg-use-tag/node.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div id="root">
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="icon"
>
<use xlink:href="#icon-home"></use>
</svg>
</div>
</div>
<div style="position: absolute; width: 0; height: 0; overflow: hidden">
<svg
style="position: absolute; width: 0; height: 0; overflow: hidden"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<symbol id="icon-home" viewBox="0 0 26 28">
<title>home</title>
<path
d="M22 15.5v7.5c0 0.547-0.453 1-1 1h-6v-6h-4v6h-6c-0.547 0-1-0.453-1-1v-7.5c0-0.031 0.016-0.063 0.016-0.094l8.984-7.406 8.984 7.406c0.016 0.031 0.016 0.063 0.016 0.094zM25.484 14.422l-0.969 1.156c-0.078 0.094-0.203 0.156-0.328 0.172h-0.047c-0.125 0-0.234-0.031-0.328-0.109l-10.813-9.016-10.813 9.016c-0.109 0.078-0.234 0.125-0.375 0.109-0.125-0.016-0.25-0.078-0.328-0.172l-0.969-1.156c-0.172-0.203-0.141-0.531 0.063-0.703l11.234-9.359c0.656-0.547 1.719-0.547 2.375 0l3.813 3.187v-3.047c0-0.281 0.219-0.5 0.5-0.5h3c0.281 0 0.5 0.219 0.5 0.5v6.375l3.422 2.844c0.203 0.172 0.234 0.5 0.063 0.703z"
></path>
</symbol>
</defs>
</svg>
</div>
27 changes: 27 additions & 0 deletions test/resources/svg-use-tag/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#dom-node {
width: 100px;
overflow: hidden;
}

#root {
border: 1px solid red;
position: relative;
height: 100px;
}

svg {
width: 100%;
height: 100%;
}

.icon {
display: inline-block;
width: 0.9285714285714285em;
height: 1em;
stroke-width: 0;
stroke: currentColor;
fill: currentColor;
vertical-align: middle;
top: -1px;
position: relative;
}
11 changes: 11 additions & 0 deletions test/spec/svg.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,15 @@ describe('work with svg element', () => {
.then(done)
.catch(done)
})

it('should render SVG use tags', function (done) {
bootstrap(
'svg-use-tag/node.html',
'svg-use-tag/style.css',
'svg-use-tag/image',
)
.then(renderAndCheck)
.then(done)
.catch(done)
})
})

0 comments on commit aec6fa1

Please sign in to comment.