Skip to content

Instantly share code, notes, and snippets.

@danalloway
Created April 7, 2018 15:50
Show Gist options
  • Select an option

  • Save danalloway/40402632adfb4bf5d9578210cd3dbc14 to your computer and use it in GitHub Desktop.

Select an option

Save danalloway/40402632adfb4bf5d9578210cd3dbc14 to your computer and use it in GitHub Desktop.

Revisions

  1. danalloway revised this gist Apr 7, 2018. No changes.
  2. danalloway created this gist Apr 7, 2018.
    149 changes: 149 additions & 0 deletions font-awesome.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,149 @@
    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