Skip to content

Commit 180d508

Browse files
committed
feat(updateNode): add function to update an existing DOM node
1 parent 87016c9 commit 180d508

2 files changed

Lines changed: 92 additions & 1 deletion

File tree

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,29 @@ document.querySelector('svg').appendChild(
5959
node(frameShape)
6060
)
6161
```
62+
63+
## updateNode
64+
65+
The `updateNode` function updates the attributes of a SVG DOM node given
66+
a Frame Shape.
67+
68+
```js
69+
import { updateNode } from 'wilderness-dom-node'
70+
71+
const frameShape = {
72+
attributes: {
73+
fill: 'yellow'
74+
},
75+
points: [
76+
{ x: 20, y: 20, moveTo: true }
77+
{ x: 80, y: 20 },
78+
{ x: 80, y: 80 },
79+
{ x: 20, y: 80 },
80+
{ x: 20, y: 20 }
81+
]
82+
}
83+
84+
document.querySelector('svg').appendChild(
85+
updateNode(document.querySelector('.blue-square'), frameShape)
86+
)
87+
```

src/index.js

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,30 @@ const nodeTypes = [
7979
*/
8080
const coreProps = type => nodeTypes.filter(node => node.type === type)[ 0 ].coreProps
8181

82+
/**
83+
* Diffs two objects and returns an object with remove and update props.
84+
*
85+
* @param {Object} current
86+
* @param {Object} next
87+
*
88+
* @returns {Object}
89+
*
90+
* @example
91+
* diff(current, next)
92+
*/
93+
const diff = (current, next) => {
94+
const currentKeys = Object.keys(current)
95+
const nextKeys = Object.keys(next)
96+
const remove = currentKeys.filter(k => nextKeys.indexOf(k) === -1)
97+
98+
const update = nextKeys.filter(k => (
99+
currentKeys.indexOf(k) !== -1 ||
100+
current[ k ] !== next[ k ]
101+
))
102+
103+
return { remove, update }
104+
}
105+
82106
/**
83107
* Creates a FrameShape from a Node.
84108
*
@@ -220,6 +244,47 @@ const removeCoreProps = (type, attributes) => {
220244
return result
221245
}
222246

247+
/**
248+
* Updates a Node from a FrameShape.
249+
*
250+
* @param {Node} el
251+
* @param {FrameShape} frameShape
252+
*
253+
* @returns {Node}
254+
*
255+
* @example
256+
* updateNode()
257+
*/
258+
const updateNode = (el, { attributes: nextAttributes, childFrameShapes, points }) => {
259+
if (childFrameShapes) {
260+
const childNodes = [ ...el.childNodes ].filter(validNode)
261+
262+
childFrameShapes.map((childFrameShape, i) => {
263+
updateNode(childNodes[ i ], childFrameShape)
264+
})
265+
} else {
266+
const nextPath = toPath(points)
267+
268+
if (nextPath !== el.getAttribute('d')) {
269+
el.setAttribute('d', nextPath)
270+
}
271+
}
272+
273+
const { attributes: currentAttributes } = el
274+
275+
const { remove, update } = diff(currentAttributes, nextAttributes)
276+
277+
remove.map(attr => {
278+
el.removeAttribute(attr)
279+
})
280+
281+
update.map(attr => {
282+
el.setAttribute(attr, nextAttributes[ attr ])
283+
})
284+
285+
return el
286+
}
287+
223288
/**
224289
* Is the node one of the accepted node types?
225290
*
@@ -232,4 +297,4 @@ const removeCoreProps = (type, attributes) => {
232297
*/
233298
const validNode = ({ nodeName }) => nodeTypes.map(({ name }) => name).indexOf(nodeName) !== -1
234299

235-
export { frameShape, node }
300+
export { frameShape, node, updateNode }

0 commit comments

Comments
 (0)