Skip to content

Instantly share code, notes, and snippets.

@sergey-shpak
Created October 9, 2018 00:08
Show Gist options
  • Save sergey-shpak/f16cca595c05387928fb893560bd28ec to your computer and use it in GitHub Desktop.
Save sergey-shpak/f16cca595c05387928fb893560bd28ec to your computer and use it in GitHub Desktop.
Hyperapp DOM Observer Subscription (MutationObserver) Implementation
import { app, h } from 'hyperapp'; // V2
// DOM Effect
// Observer Implementation
// Will be moved to subscriptions package
const find = (query, nodes, cb) => nodes.forEach(node => {
if(node.nodeType !== 1 ) return
if(Object.keys(query).every(key => node.getAttribute(key) === query[key]))
return cb(node)
else if(node.childNodes.length)
return find(query, node.childNodes, cb)
})
const onChange = (select, cb) => mutations => mutations.forEach(
({ target, type, attributeName, oldValue, addedNodes, removedNodes }) => {
type === 'attributes' &&
find(select, [target], node =>
cb(node, { type: 'updated', attribute: [oldValue, attributeName] }))
addedNodes.length &&
find(select, addedNodes, node => cb(node, { type: 'added' }))
removedNodes.length &&
find(select, removedNodes, node => cb(node, { type: 'removed' }))
})
const observe = ({ select, target, action, config }, dispatch) => {
const observer = new MutationObserver(
onChange(select, (element, props) => dispatch([action, element], props))
)
observer.observe(target, {
attributes: true, childList: true, subtree: true, ...config
})
return () => observer.disconnect();
}
const DOM = {
observe: props => ({ ...props, effect: observe })
}
// Time effects
// Just to tick ;)
// Also will be imported from subscriptions package
const tick = ({ action, ms }, dispatch) => {
const id = setInterval(() => dispatch(action), ms)
return () => clearInterval(id)
}
const Time = {
tick: props => ({ ...props, effect: tick })
}
// APPLICATION
// `Lifecycle` events using DOM observer
const lifecycle = (state, element, change) => {
console.log(element, change)
}
const increment = state => ({ inc: ++state.inc })
const container = document.body
app({
init: { inc: 0 },
view: state => <div>
{ state.inc < 5 &&
<div id="someid" class={ state.inc } >
Removed in 5 ({ state.inc })
</div>
}
</div>,
subscriptions: state => [
DOM.observe({
select: { id: 'someid' },
target: container,
action: lifecycle
}),
Time.tick({
action: increment,
ms: 1000
})
],
container
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment