first commit
This commit is contained in:
+262
@@ -0,0 +1,262 @@
|
||||
import { classList, objectWithKey } from '../utils'
|
||||
import { computed, defineComponent, watch } from 'vue'
|
||||
import { icon as faIcon, parse as faParse } from '@fortawesome/fontawesome-svg-core'
|
||||
|
||||
import convert from '../converter'
|
||||
import log from '../logger'
|
||||
|
||||
function normalizeIconArgs(icon) {
|
||||
if (icon && typeof icon === 'object' && icon.prefix && icon.iconName && icon.icon) {
|
||||
return icon
|
||||
}
|
||||
|
||||
if (faParse.icon) {
|
||||
return faParse.icon(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 }
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FontAwesomeIcon',
|
||||
|
||||
props: {
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// the fixedWidth property has been deprecated as of version 7
|
||||
fixedWidth: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
flip: {
|
||||
type: [Boolean, String],
|
||||
default: false,
|
||||
validator: (value) => [true, false, 'horizontal', 'vertical', 'both'].indexOf(value) > -1
|
||||
},
|
||||
icon: {
|
||||
type: [Object, Array, String],
|
||||
required: true
|
||||
},
|
||||
mask: {
|
||||
type: [Object, Array, String],
|
||||
default: null
|
||||
},
|
||||
maskId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
listItem: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
pull: {
|
||||
type: String,
|
||||
default: null,
|
||||
validator: (value) => ['right', 'left'].indexOf(value) > -1
|
||||
},
|
||||
pulse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
rotation: {
|
||||
type: [String, Number],
|
||||
default: null,
|
||||
validator: (value) => [90, 180, 270].indexOf(Number.parseInt(value, 10)) > -1
|
||||
},
|
||||
// the rotateBy property is only supported in version 7.0.0 and later
|
||||
rotateBy: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
swapOpacity: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: null,
|
||||
validator: (value) => ['2xs', 'xs', 'sm', 'lg', 'xl', '2xl', '1x', '2x', '3x', '4x', '5x', '6x', '7x', '8x', '9x', '10x'].indexOf(value) > -1
|
||||
},
|
||||
spin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
transform: {
|
||||
type: [String, Object],
|
||||
default: null
|
||||
},
|
||||
symbol: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
titleId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
inverse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
bounce: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
shake: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
beat: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fade: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
beatFade: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
flash: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
spinPulse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
spinReverse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// the widthAuto property is only supported in version 7.0.0 and later
|
||||
widthAuto: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// the canvasSquare and canvasRoomy properties are only supported in version 7.3.0 and later
|
||||
canvasSquare: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
canvasRoomy: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
gradientFill: {
|
||||
type: Object,
|
||||
default: null,
|
||||
validator(value) {
|
||||
if (typeof value.id !== 'string' || !value.id) {
|
||||
console.warn('FontAwesomeIcon: gradientFill.id must be a non-empty string')
|
||||
return false
|
||||
}
|
||||
if (value.type !== 'linear' && value.type !== 'radial') {
|
||||
console.warn('FontAwesomeIcon: gradientFill.type must be "linear" or "radial"')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
},
|
||||
// the following animation properties are only supported in version 7.3.0 and later
|
||||
flip360: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
buzz: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
float: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
jello: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
spinSnap: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
spinSnap4: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
spinSnap8: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
swing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
wag: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
setup(props, { attrs }) {
|
||||
const icon = computed(() => normalizeIconArgs(props.icon))
|
||||
const classes = computed(() => objectWithKey('classes', classList(props)))
|
||||
const transform = computed(() => objectWithKey('transform', typeof props.transform === 'string' ? faParse.transform(props.transform) : props.transform))
|
||||
const mask = computed(() => objectWithKey('mask', normalizeIconArgs(props.mask)))
|
||||
|
||||
const renderedIcon = computed(() => {
|
||||
const iconProps = {
|
||||
...classes.value,
|
||||
...transform.value,
|
||||
...mask.value,
|
||||
symbol: props.symbol,
|
||||
maskId: props.maskId
|
||||
}
|
||||
|
||||
// the title attribute will only apply to versions prior to version 7.0.0
|
||||
iconProps.title = props.title
|
||||
iconProps.titleId = props.titleId
|
||||
|
||||
return faIcon(icon.value, iconProps)
|
||||
})
|
||||
|
||||
watch(
|
||||
renderedIcon,
|
||||
(value) => {
|
||||
if (!value) {
|
||||
return log('Could not find one or more icon(s)', icon.value, mask.value)
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
if (props.gradientFill && props.symbol) {
|
||||
log('gradientFill is not supported when symbol is true and will be ignored')
|
||||
}
|
||||
|
||||
const vnode = computed(() =>
|
||||
renderedIcon.value ? convert(renderedIcon.value.abstract[0], { gradientFill: props.symbol ? null : props.gradientFill }, attrs) : null
|
||||
)
|
||||
|
||||
return () => vnode.value
|
||||
}
|
||||
})
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { computed, defineComponent, h } from 'vue'
|
||||
import { config } from '@fortawesome/fontawesome-svg-core'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FontAwesomeLayers',
|
||||
|
||||
props: {
|
||||
fixedWidth: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
setup(props, { slots }) {
|
||||
const { familyPrefix } = config
|
||||
|
||||
const className = computed(() => [`${familyPrefix}-layers`, ...(props.fixedWidth ? [`${familyPrefix}-fw`] : [])])
|
||||
|
||||
return () => h('div', { class: className.value }, slots.default ? slots.default() : [])
|
||||
}
|
||||
})
|
||||
Generated
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
import { config, parse, text } from '@fortawesome/fontawesome-svg-core'
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import convert from '../converter'
|
||||
import { objectWithKey } from '../utils'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FontAwesomeLayersText',
|
||||
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
transform: {
|
||||
type: [String, Object],
|
||||
default: null
|
||||
},
|
||||
counter: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
position: {
|
||||
type: String,
|
||||
default: null,
|
||||
validator: (value) => ['bottom-left', 'bottom-right', 'top-left', 'top-right'].indexOf(value) > -1
|
||||
}
|
||||
},
|
||||
|
||||
setup(props, { attrs }) {
|
||||
const { familyPrefix } = config
|
||||
|
||||
const classes = computed(() =>
|
||||
objectWithKey('classes', [
|
||||
...(props.counter ? [`${familyPrefix}-layers-counter`] : []),
|
||||
...(props.position ? [`${familyPrefix}-layers-${props.position}`] : [])
|
||||
])
|
||||
)
|
||||
const transform = computed(() => objectWithKey('transform', typeof props.transform === 'string' ? parse.transform(props.transform) : props.transform))
|
||||
const abstractElement = computed(() => {
|
||||
const { abstract } = text(props.value.toString(), { ...transform.value, ...classes.value })
|
||||
if (props.counter) {
|
||||
abstract[0].attributes.class = abstract[0].attributes.class.replace('fa-layers-text', '')
|
||||
}
|
||||
return abstract[0]
|
||||
})
|
||||
|
||||
const vnode = computed(() => convert(abstractElement.value, {}, attrs))
|
||||
return () => vnode.value
|
||||
}
|
||||
})
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
import { h } from 'vue'
|
||||
import humps from 'humps'
|
||||
|
||||
/**
|
||||
* Converts a CSS style into a plain Javascript object.
|
||||
* @param {String} style The style to converts into a plain Javascript object.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function styleToObject(style) {
|
||||
return style
|
||||
.split(';')
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s)
|
||||
.reduce((output, pair) => {
|
||||
const idx = pair.indexOf(':')
|
||||
const prop = humps.camelize(pair.slice(0, idx))
|
||||
const value = pair.slice(idx + 1).trim()
|
||||
|
||||
output[prop] = value
|
||||
return output
|
||||
}, {})
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a CSS class list into a plain Javascript object.
|
||||
* @param {Array<String>} classes The class list to convert.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function classToObject(classes) {
|
||||
return classes.split(/\s+/).reduce((output, className) => {
|
||||
output[className] = true
|
||||
return output
|
||||
}, {})
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vue VNode for an SVG gradient stop element.
|
||||
* @param {Object} stop The gradient stop definition.
|
||||
* @param {string|number} stop.offset The offset of the stop.
|
||||
* @param {string} stop.color The color of the stop.
|
||||
* @param {number} [stop.opacity] The opacity of the stop.
|
||||
* @param {number} index The index of the stop.
|
||||
* @returns {VNode}
|
||||
*/
|
||||
function createGradientStop(stop, index) {
|
||||
return h('stop', {
|
||||
'key': `${index}-${stop.offset}`,
|
||||
'offset': stop.offset,
|
||||
'stop-color': stop.color,
|
||||
...(stop.opacity !== undefined && { 'stop-opacity': stop.opacity })
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively removes the fill attribute from all path elements in an abstract element tree.
|
||||
* @param {AbstractElement | String} abstractElement
|
||||
* @returns {AbstractElement | String}
|
||||
*/
|
||||
function stripFillsFromPaths(abstractElement) {
|
||||
if (typeof abstractElement === 'string') return abstractElement
|
||||
|
||||
const children = (abstractElement.children || []).map(stripFillsFromPaths)
|
||||
|
||||
if (abstractElement.tag === 'path' && abstractElement.attributes && 'fill' in abstractElement.attributes) {
|
||||
return { ...abstractElement, attributes: { ...abstractElement.attributes, fill: undefined }, children }
|
||||
}
|
||||
|
||||
return { ...abstractElement, children }
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a FontAwesome abstract element of an icon into a Vue VNode.
|
||||
* @param {AbstractElement | String} abstractElement The element to convert.
|
||||
* @param {Object} props Options including gradientFill and any extra VNode props.
|
||||
* @param {Object} attrs The user-defined native HTML attributes.
|
||||
* @returns {VNode}
|
||||
*/
|
||||
export default function convert(abstractElement, props = {}, attrs = {}) {
|
||||
// If the abstract element is a string, we'll just return a string render function
|
||||
if (typeof abstractElement === 'string') {
|
||||
return abstractElement
|
||||
}
|
||||
|
||||
const { gradientFill = null, ...renderProps } = props
|
||||
|
||||
// If a gradientFill (or fill attr) is provided, strip fill from all descendant path elements
|
||||
// up front so the gradient/fill takes precedence over the icon's built-in fill
|
||||
const shouldStripFills = !!gradientFill || 'fill' in attrs
|
||||
const element = shouldStripFills ? stripFillsFromPaths(abstractElement) : abstractElement
|
||||
|
||||
// Converting abstract element children into Vue VNodes
|
||||
const children = (element.children || []).map((child) => convert(child, {}, {}))
|
||||
|
||||
// Converting abstract element attributes into valid Vue format
|
||||
const mixins = Object.keys(element.attributes || {}).reduce(
|
||||
(mixins, key) => {
|
||||
const value = element.attributes[key]
|
||||
|
||||
switch (key) {
|
||||
case 'class':
|
||||
mixins.class = classToObject(value)
|
||||
break
|
||||
case 'style':
|
||||
mixins.style = styleToObject(value)
|
||||
break
|
||||
default:
|
||||
mixins.attrs[key] = value
|
||||
}
|
||||
|
||||
return mixins
|
||||
},
|
||||
{
|
||||
attrs: {},
|
||||
class: {},
|
||||
style: {}
|
||||
}
|
||||
)
|
||||
|
||||
// Now, we'll return the VNode
|
||||
const { class: _aClass = {}, style: aStyle = {}, ...otherAttrs } = attrs
|
||||
|
||||
// If a valid gradientFill is provided, inject the gradient element and set fill to reference it
|
||||
if (gradientFill && gradientFill.id && (gradientFill.type === 'linear' || gradientFill.type === 'radial')) {
|
||||
const { type: gradientType, stops = [], id, ...gradientProps } = gradientFill
|
||||
const gradientTag = gradientType === 'linear' ? 'linearGradient' : 'radialGradient'
|
||||
const gradientVNode = h(gradientTag, { ...gradientProps, id }, stops.map(createGradientStop))
|
||||
|
||||
return h(
|
||||
element.tag,
|
||||
{
|
||||
...renderProps,
|
||||
class: mixins.class,
|
||||
style: { ...mixins.style, ...aStyle },
|
||||
...mixins.attrs,
|
||||
...otherAttrs,
|
||||
fill: `url(#${id})`
|
||||
},
|
||||
[gradientVNode, ...children]
|
||||
)
|
||||
}
|
||||
|
||||
return h(
|
||||
abstractElement.tag,
|
||||
{
|
||||
...renderProps,
|
||||
class: mixins.class,
|
||||
style: { ...mixins.style, ...aStyle },
|
||||
...mixins.attrs,
|
||||
...otherAttrs
|
||||
},
|
||||
children
|
||||
)
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export { default as FontAwesomeIcon } from './components/FontAwesomeIcon'
|
||||
export { default as FontAwesomeLayers } from './components/FontAwesomeLayers'
|
||||
export { default as FontAwesomeLayersText } from './components/FontAwesomeLayersText'
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
let PRODUCTION = false
|
||||
|
||||
try {
|
||||
PRODUCTION = process.env.NODE_ENV === 'production'
|
||||
} catch (e) { }
|
||||
|
||||
export default function (...args) {
|
||||
if (!PRODUCTION && console && typeof console.error === 'function') {
|
||||
console.error(...args)
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
export function objectWithKey(key, value) {
|
||||
return (Array.isArray(value) && value.length > 0) || (!Array.isArray(value) && value) ? { [key]: value } : {}
|
||||
}
|
||||
|
||||
export function classList(props) {
|
||||
let classes = {
|
||||
'fa-spin': props.spin,
|
||||
'fa-pulse': props.pulse,
|
||||
// the fixedWidth property has been deprecated as of version 7.0.0
|
||||
'fa-fw': props.fixedWidth,
|
||||
'fa-border': props.border,
|
||||
'fa-li': props.listItem,
|
||||
'fa-inverse': props.inverse,
|
||||
'fa-flip': props.flip === true,
|
||||
'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-rotate-by': props.rotateBy,
|
||||
[`fa-pull-${props.pull}`]: props.pull !== null,
|
||||
'fa-swap-opacity': props.swapOpacity,
|
||||
'fa-bounce': props.bounce,
|
||||
'fa-shake': props.shake,
|
||||
'fa-beat': props.beat,
|
||||
'fa-fade': props.fade,
|
||||
'fa-beat-fade': props.beatFade,
|
||||
'fa-flash': props.flash,
|
||||
'fa-spin-pulse': props.spinPulse,
|
||||
'fa-spin-reverse': props.spinReverse,
|
||||
// the widthAuto property is only supported in version 7.0.0 and later
|
||||
'fa-width-auto': props.widthAuto,
|
||||
// the canvasSquare and canvasRoomy properties are only supported in version 7.3.0 and later
|
||||
'fa-canvas-square': props.canvasSquare,
|
||||
'fa-canvas-roomy': props.canvasRoomy,
|
||||
// the following animations are only supported in version 7.3.0 and later
|
||||
'fa-flip-360': props.flip360,
|
||||
'fa-buzz': props.buzz,
|
||||
'fa-float': props.float,
|
||||
'fa-jello': props.jello,
|
||||
'fa-spin-snap': props.spinSnap,
|
||||
'fa-spin-snap-4': props.spinSnap4,
|
||||
'fa-spin-snap-8': props.spinSnap8,
|
||||
'fa-swing': props.swing,
|
||||
'fa-wag': props.wag
|
||||
}
|
||||
|
||||
return Object.keys(classes)
|
||||
.map((key) => (classes[key] ? key : null))
|
||||
.filter((key) => key)
|
||||
}
|
||||
|
||||
export function addStaticClass(to, what) {
|
||||
const val = (to || '').length === 0 ? [] : [to]
|
||||
|
||||
return val.concat(what).join(' ')
|
||||
}
|
||||
Reference in New Issue
Block a user