Created
April 7, 2018 15:50
-
-
Save danalloway/40402632adfb4bf5d9578210cd3dbc14 to your computer and use it in GitHub Desktop.
FontAwesome v5 Component I'm using with Preact
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
import { h, createElement } from 'preact' | |
import humps from 'humps' | |
import fontawesome from '@fortawesome/fontawesome' | |
// icons | |
import faClipboardList from '@fortawesome/fontawesome-pro-solid/faClipboardList' | |
import faPlus from '@fortawesome/fontawesome-pro-solid/faPlus' | |
fontawesome.library.add(faClipboardList, faPlus) | |
const Icon = props => { | |
const { icon: iconArgs, mask: maskArgs, symbol, class: className } = props | |
const icon = normalizeIconArgs(iconArgs) | |
const classes = objectWithKey('classes', [ | |
...classList(props), | |
...className.split(' ') | |
]) | |
const transform = objectWithKey( | |
'transform', | |
typeof props.transform === 'string' | |
? fontawesome.parse.transform(props.transform) | |
: props.transform | |
) | |
const mask = objectWithKey('mask', normalizeIconArgs(maskArgs)) | |
const renderedIcon = fontawesome.icon(icon, { | |
...classes, | |
...transform, | |
...mask, | |
symbol | |
}) | |
const { abstract } = renderedIcon | |
const convertCurry = convert.bind(null, createElement) | |
const extraProps = {} | |
Object.keys(props).forEach(key => { | |
if (!Icon.defaultProps.hasOwnProperty(key)) extraProps[key] = props[key] | |
}) | |
return convertCurry(abstract[0], extraProps) | |
} | |
const normalizeIconArgs = icon => { | |
if (icon === null) { | |
return null | |
} | |
if (typeof icon === 'object' && icon.prefix && icon.iconName) { | |
return icon | |
} | |
if (Array.isArray(icon) && icon.length === 2) { | |
return { prefix: icon[0], iconName: icon[1] } | |
} | |
if (typeof icon === 'string') { | |
return { prefix: 'fas', iconName: icon } | |
} | |
} | |
const objectWithKey = (key, value) => { | |
return (Array.isArray(value) && value.length > 0) || | |
(!Array.isArray(value) && value) | |
? { [key]: value } | |
: {} | |
} | |
const classList = props => { | |
let classes = { | |
'fa-spin': props.spin, | |
'fa-pulse': props.pulse, | |
'fa-fw': props.fixedWidth, | |
'fa-border': props.border, | |
'fa-li': props.listItem, | |
'fa-flip-horizontal': | |
props.flip === 'horizontal' || props.flip === 'both', | |
'fa-flip-vertical': props.flip === 'vertical' || props.flip === 'both', | |
[`fa-${props.size}`]: props.size !== null, | |
[`fa-rotate-${props.rotation}`]: props.rotation !== null, | |
[`fa-pull-${props.pull}`]: props.pull !== null | |
} | |
return Object.keys(classes) | |
.map(key => (classes[key] ? key : null)) | |
.filter(key => key) | |
} | |
const convert = (createElement, element, extraProps = {}) => { | |
const children = (element.children || []).map( | |
convert.bind(null, createElement) | |
) | |
const mixins = Object.keys(element.attributes || {}).reduce( | |
(acc, key) => { | |
const val = element.attributes[key] | |
switch (key) { | |
case 'class': | |
acc.attrs['className'] = val | |
delete element.attributes['class'] | |
break | |
case 'style': | |
acc.attrs['style'] = styleToObject(val) | |
break | |
default: | |
if ( | |
key.indexOf('aria-') === 0 || | |
key.indexOf('data-') === 0 | |
) { | |
acc.attrs[key.toLowerCase()] = val | |
} else { | |
acc.attrs[humps.camelize(key)] = val | |
} | |
} | |
return acc | |
}, | |
{ attrs: {} } | |
) | |
const { style: existingStyle = {}, ...remaining } = extraProps | |
mixins.attrs['style'] = { ...mixins.attrs['style'], ...existingStyle } | |
return createElement( | |
element.tag, | |
{ ...mixins.attrs, ...remaining }, | |
...children | |
) | |
} | |
Icon.defaultProps = { | |
border: false, | |
class: '', | |
mask: null, | |
fixedWidth: false, | |
flip: null, | |
icon: null, | |
listItem: false, | |
pull: null, | |
pulse: false, | |
name: '', | |
rotation: null, | |
size: null, | |
spin: false, | |
symbol: false, | |
transform: null | |
} | |
export default Icon |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment