Skip to content

Instantly share code, notes, and snippets.

@dead-claudia
Last active January 23, 2020 03:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dead-claudia/c2ded4a72065a3a9e8fded7e7cb5be75 to your computer and use it in GitHub Desktop.
Save dead-claudia/c2ded4a72065a3a9e8fded7e7cb5be75 to your computer and use it in GitHub Desktop.
Mithril port of react-fontawesome
// This is a direct API port of https://github.com/FortAwesome/react-fontawesome
// to Mithril, with a few optimizations for faster vnode creation and more
// efficient normalization. It's also combined into a single UMD file and
// written to support a pure ES5 environment without transpiling. It's less than
// 200 lines of code excluding this long introductory comment, and is about
// 1.2KB min+gzip.
//
// Here's a few example vnodes:
//
// ```js
// m(FontAwesomeIcon, {icon: "spinner", size: "xs"})
// m(FontAwesomeIcon, {icon: "spinner", fixedWidth: true})
// m(FontAwesomeIcon, {icon: faCoffee})
// ```
//
// This file is licensed under the following license (ISC License):
//
// Copyright (c) 2019 and later, Isiah Meadows <contact@isiahmeadows.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
;(function (factory) {
if (typeof module === "object" && module.exports) {
module.exports = factory(
require("mithril/render/vnode"),
require("@fortawesome/fontawesome-svg-core")
)
} else {
window.FontAwesomeIcon = factory(m.vnode, FontAwesome)
}
})(function (Vnode, FontAwesome) {
"use strict"
var magicProp = new RegExp("^(" + [
// Mithril keys
"key",
"oninit", "oncreate",
"onbeforeupdate", "onupdate",
"onbeforeremove", "onremove",
// Style keys
"class", "className",
// Font Awesome keys
"border", "mask", "fixedWidth", "inverse", "flip", "icon", "listItem",
"pull", "pulse", "rotation", "size", "spin", "symbol", "title", "transform",
].join("|") + ")$")
var shouldLog = console && typeof console.error === "function"
try {
shouldLog = process.env.NODE_ENV !== "production"
} catch (e) {
// ignore
}
return {
view: function (vnode) {
var iconOpts = {
symbol: vnode.attrs.symbol,
title: vnode.attrs.title,
}
var classObject = Object.create(null)
if (vnode.attrs.spin) classObject["fa-spin"] = true
if (vnode.attrs.pulse) classObject["fa-pulse"] = true
if (vnode.attrs.fixedWidth) classObject["fa-fw"] = true
if (vnode.attrs.inverse) classObject["fa-inverse"] = true
if (vnode.attrs.border) classObject["fa-border"] = true
if (vnode.attrs.listItem) classObject["fa-li"] = true
if (vnode.attrs.flip === "horizontal" || vnode.attrs.flip === "both") {
classObject["fa-flip-horizontal"] = true
}
if (vnode.attrs.flip === "vertical" || vnode.attrs.flip === "both") {
classObject["fa-flip-vertical"] = true
}
if (vnode.attrs.size) {
classObject["fa-" + vnode.attrs.size] = true
}
if (vnode.attrs.rotation) {
classObject["fa-rotate-" + vnode.attrs.rotation] = true
}
if (vnode.attrs.pull) {
classObject["fa-pull-" + vnode.attrs.pull] = true
}
appendClassString(classObject, vnode.attrs.class)
appendClassString(classObject, vnode.attrs.className)
var classes = Object.keys(classObject)
if (classes.length) iconOpts.classes = classes
var mask = normalizeIconArgs(vnode.attrs.mask)
if (mask) iconOpts.mask = mask
var transform = typeof vnode.attrs.transform === "string"
? FontAwesome.parse.transform(vnode.attrs.transform)
: vnode.attrs.transform
if (Array.isArray(transform) ? transform.length : transform) {
iconOpts.transform = transform
}
var iconLookup = normalizeIconArgs(vnode.attrs.icon)
var renderedIcon = FontAwesome.icon(iconLookup, iconOpts)
if (!renderedIcon) {
if (shouldLog) console.error("Could not find icon", iconLookup)
return void 0
}
var result = convert(renderedIcon.abstract[0])
if (typeof result !== "string") {
for (var key in vnode.attrs) {
if (Object.prototype.hasOwnProperty.call(vnode.attrs, key)) {
if (key === "style") {
for (key in vnode.attrs.style) {
if (Object.prototype.hasOwnProperty.call(
vnode.attrs.style, key
)) {
result.attrs.style[key] = vnode.attrs.style[key]
}
}
} else if (!magicProp.test(key)) {
result.attrs.style[key] = vnode.attrs[key]
}
}
}
}
return result
}
}
function convert(element) {
if (typeof element === "string") {
return Vnode("#", void 0, void 0, element, void 0, void 0)
}
var hasKey = false
for (var key in element.attributes) {
if (Object.prototype.hasOwnProperty.call(element.attributes, key)) {
hasKey = true
if (key === "style") {
var properties = element.attributes[key].split(";")
var target = element.attributes[key] = {}
for (var i = 0; i < properties.length; i++) {
var pair = properties[i]
if (!/^\s*(:\s*)?$/.test(pair)) {
var index = pair.indexOf(":")
target[pair.slice(0, index).trim()] =
pair.slice(index + 1).trim()
}
}
}
}
}
var children, text
if (element.children && element.children.length) {
if (
element.children.length === 1 &&
typeof element.children[0] === "string"
) {
text = element.children[0]
} else {
children = element.children
for (i = 0; i < children.length; i++) {
children[i] = convert(children[i])
}
}
}
return Vnode(
element.tag, void 0, hasKey ? element.attributes : void 0,
children, text, void 0
)
}
function appendClassString(classObject, string) {
if (!string) return
var list = string.trim().split(/\s+/g)
for (var i = 0; i < list.length; i++) classObject[list[i]] = true
}
function normalizeIconArgs(icon) {
if (typeof icon === "string") {
return {prefix: "fas", iconName: icon}
} else if (Array.isArray(icon) && icon.length === 2) {
return {prefix: icon[0], iconName: icon[1]}
} else if (typeof icon === "object" && icon.prefix && icon.iconName) {
return icon
} else {
return void 0
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment