preact-layout
Version:
Small and simple layout library for preact
80 lines (71 loc) • 2.69 kB
JSX
import { h, Component } from 'preact'
function Layout({className, recurse, children, ...props}, context) {
const { main, sections } = getSections(children)
processNode(main, sections, { ...context }, recurse)
return children && children.length === 1 ? children[0] : (
<div className={className || 'Layout'}>{children}</div>
)
}
function Section({type, children, ...props}, context) {return (
children && (children.length === 1) ? children[0] : (
<div {...props}>{children}</div>
)
)}
function getSections(n, result) {
if (!result) result = {sections:[]}
if (n.nodeName === Section) {
if (n.attributes && n.attributes.type) result.sections.push(n)
else result.main = n
}
const children = Array.isArray(n) ? n : n.children
children && children.forEach(c => {
getSections(c, result)
})
return result
}
function processNode(node, sections, context, recurse, collectOnly, results) {
const leftovers = [], postProcess = !results
context = context || {}
if (recurse === undefined) recurse = 9
results = results || {}
sections.forEach(s => results[s.attributes.type] = results[s.attributes.type] || s.children || [])
node && node.children && node.children.forEach(n => {
if (isContribution(n, sections)) {
if (! results[n.nodeName]) results[n.nodeName] = []
if (n.attributes && n.attributes.append) results[n.nodeName].push.apply(results[n.nodeName], n.children || [])
else if (n.attributes && n.attributes.prepend) results[n.nodeName].unshift.apply(results[n.nodeName], n.children || [])
else results[n.nodeName] = n.children || []
return // continue
}
leftovers.push(n)
if (typeof n.nodeName == 'function' && recurse) {
let props = { ...n.nodeName.defaultProps, ...n.attributes, children:n.children }
if (n.nodeName.prototype && typeof n.nodeName.prototype.render == 'function') {
let rn, c = new n.nodeName(props, context);
c.props = props;
c.context = context;
if (c.componentWillMount) c.componentWillMount();
n = c.render(c.props, c.state, c.context);
if (c.getChildContext) context = { ...context, ...c.getChildContext() }
}
else n = n.nodeName(props, context)
recurse--
}
processNode(n, sections, context, recurse, collectOnly, results)
})
if (! collectOnly) {
if (node.children) node.children = leftovers
if (postProcess) sections.forEach(s => s.children = results[s.attributes.type])
}
return results
}
function isContribution(n, sections) {
return sections.filter(s => n.nodeName === s.attributes.type).length > 0
}
export {
Layout,
Section,
getSections,
isContribution,
processNode
}