Last active
January 21, 2020 17:14
-
-
Save fuunnx/e81c86cc46a485786f8193563d550680 to your computer and use it in GitHub Desktop.
Higher order vnodes utility functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const typeButton = extended({ | |
attrs: { | |
type: 'button', | |
}, | |
}) | |
const blueBackground = extended({ | |
style: { | |
'background-color': 'blue', | |
'color': 'white', | |
}, | |
}) | |
const lotOfPadding = extended({ | |
style: { | |
'padding': '20px', | |
}, | |
}) | |
const conditionnalStyle = styled({ | |
'border': ({attrs: {disabled}} : {attrs: {disabled: Boolean}}) => disabled | |
? '2px solid #fff' | |
: '10px dotted #000', | |
}) | |
const hasCookies = modifier({children: (xs: any[]) => (['🍪 ', ...xs, ' 🍪'])}) | |
const defaultButton = typeButton(button) | |
const primaryButton = blueBackground(lotOfPadding(defaultButton)) | |
const cookieButton = hasCookies(primaryButton) | |
const conditionnedButton = conditionnalStyle(defaultButton) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const vNode = (fn: Function) => (...args: any[]) => fn(...identifyArgs(...args)) | |
export function styled (style_: any) { | |
return modifier({ | |
attributes: context => { | |
const style = mapObj((prop: Function | String) => | |
typeof prop === 'function' | |
? String(prop(context)) | |
: String(prop) | |
)(style_) | |
return mergeDeep({style})(context) | |
}, | |
}) | |
} | |
export function extended (...args: any[]) { | |
const [ | |
selector, | |
attributes, | |
children, | |
] = identifyArgs(...args) | |
return modifier({ | |
selector: concat(selector), | |
attributes: mergeDeep(attributes), | |
children: concat(children), | |
}) | |
} | |
export function modifier ({ | |
selector: updateSelector = (x: String) => x, | |
attributes: updateAttributes = (x: any) => x, | |
children: updateChildren = (x: any[]) => x | |
}) { | |
return (component: Function) => vNode(([sel, attrs, children_]: [String, any, any[]]) => { | |
const selector = updateSelector(sel) | |
const attributes = updateAttributes(attrs) | |
const children = updateChildren(children_) | |
return selector | |
? component(selector, attributes, children) | |
: component(attributes, children) | |
}) | |
} | |
function identifyArgs (first?: any, b?: any, c?: String[]): [String, any, any[]] { | |
let selector = '' | |
let attributes = {} | |
let children = [] | |
if (isSelector(first)) { | |
selector = first | |
if (b && c) (attributes = b, children = c) | |
if (b && Array.isArray(b) && !c) (children = b) | |
if (b && !Array.isArray(b) && !c) (attributes = b) | |
} | |
if (!isSelector(first)) { | |
if (first && b) (attributes = first, children = b) | |
if (first && Array.isArray(first) && !b) (children = first) | |
if (first && !Array.isArray(first) && !b) (attributes = first) | |
} | |
return [ | |
selector, | |
attributes, | |
children, | |
] | |
} | |
function isValidString(param: any) { | |
return typeof param === 'string' && param.length > 0 | |
} | |
function isSelector(param: any) { | |
return isValidString(param) && (param[0] === '.' || param[0] === '#') | |
} | |
function mapObj (fn: Function) { | |
return (obj: any) => Object.entries(obj).reduce((acc: any, [key, value]: [String, any]) => ({...acc, [key]: fn(value)}), {}) | |
} | |
const concat = (x: Array<String> | String) => (y: Array<String> | String) => (Array.isArray(x) && Array.isArray(y)) | |
? x.concat(y) | |
: [x, y].join('') | |
const mergeDeep = (target: any) => (source: any) => { | |
let output = Object.assign({}, target) | |
if (isObject(target) && isObject(source)) { | |
Object.keys(source).forEach(key => { | |
if (isObject(source[key])) { | |
if (!(key in target)) | |
Object.assign(output, { [key]: source[key] }) | |
else | |
output[key] = mergeDeep(target[key])(source[key]) | |
} else { | |
Object.assign(output, { [key]: source[key] }) | |
} | |
}) | |
} | |
return output | |
} | |
function isObject(item: any) { | |
return (item && typeof item === 'object' && !Array.isArray(item)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment