Skip to content

Commit

Permalink
feat(Vue Icon): add Vue Icon component
Browse files Browse the repository at this point in the history
  • Loading branch information
wzpo committed Jul 17, 2019
1 parent 8bd47c3 commit 59c292e
Show file tree
Hide file tree
Showing 10 changed files with 679 additions and 1 deletion.
3 changes: 3 additions & 0 deletions vue/src/examples.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import Badge from './lib/badge/examples/index.js';
import Button from './lib/button/examples/index.js';
import Icon from './lib/icon/examples/index.js';
import Loading from './lib/loading/examples/index.js';

const examples = [
Badge,
Button,
Icon,
Loading

];

const install = (Vue) => {
Expand Down
3 changes: 3 additions & 0 deletions vue/src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import Badge from './lib/badge/index.vue';
import Button from './lib/button/index.vue';
import Icon from './lib/icon/index.vue';
import Loading from './lib/loading/index.vue';

const components = [
Badge,
Button,
Icon,
Loading
];

Expand All @@ -22,5 +24,6 @@ export default {
install,
Badge,
Button,
Icon,
Loading
};
15 changes: 15 additions & 0 deletions vue/src/lib/icon/examples/color.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<div>
<md-icon :name="'accessories_16'" :color="'blue-50'" />
<md-icon :name="'accessories_20'" :color="'blue-50'" />
<md-icon :name="'accessories_36'" :color="'blue-50'" />
<md-icon :name="'accessories_56'" :color="'blue-50'" />
</div>
</template>

<script>
export default {
name: 'ExampleIconColor',
};
</script>

15 changes: 15 additions & 0 deletions vue/src/lib/icon/examples/default.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<div>
<md-icon :name="'accessories_16'" />
<md-icon :name="'accessories_20'" />
<md-icon :name="'accessories_36'" />
<md-icon :name="'accessories_56'" />
</div>
</template>

<script>
export default {
name: 'ExampleIconDefault',
};
</script>

12 changes: 12 additions & 0 deletions vue/src/lib/icon/examples/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Icon from '../index.vue';
import ExampleIconDefault from './default.vue';
import ExampleIconColor from './color.vue';
import ExampleIconWhite from './white.vue';

export default {
Icon,
ExampleIconDefault,
ExampleIconColor,
ExampleIconWhite
};

23 changes: 23 additions & 0 deletions vue/src/lib/icon/examples/white.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div style="background-color: #000; padding: 5px; width: fit-content;">
<md-icon
:name="'clear-active_24'"
:ariaLabel="'Clear'"
:type="'white'"
@click="handleClick"
/>
</div>
</template>

<script>
export default {
name: 'ExampleIconWhite',
methods: {
handleClick(e) {
alert('Icon 36 - clicked');
},
}
};
</script>

187 changes: 187 additions & 0 deletions vue/src/lib/icon/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<script>
import iconNames from '@momentum-ui/icons/data/iconNames.json';
import getColorValue from '@momentum-ui/utils/lib/getColorValue';
export default {
name: 'md-icon',
render: function (h) {
const {
append,
ariaLabel,
buttonClassName,
color,
className,
description,
name,
prepend,
size,
sizeOverride,
cssStyle,
title,
type,
...otherProps
} = this.$props;
const consoleHandler = (message, data) => {
/* eslint-disable no-console */
switch (message) {
case 'color-warn':
console.warn(
`[@momentum-ui/react] Icon: ${data} may not exist in the design system,` +
` please use a color name from https://momentum.design/styles/color/style`
);
break;
case 'name-error':
console.warn(
`[@momentum-ui/react] Icon: Icon ${data} does not exist in the design system.` +
` Visit https://momentum.design/styles/icons/library for a list of available icons or to request a new icon.`
);
break;
}
/* eslint-enable no-console */
};
const getSize = () => {
const defaultSize = 16;
const sizeFromName = Number(name.split('_')[1]);
return size || sizeFromName || defaultSize;
};
const getColor = () => {
if (color.startsWith('#')) {
consoleHandler('color-warn', color);
return color;
}
return getColorValue(color);
};
const getNameClass = () => {
let iconName = name.startsWith('icon-') ? name.replace(/^(icon-)/, '') : name;
if (sizeOverride) {
iconName = name.split('_')[0] + `_${getSize()}`;
}
return iconNames.includes(iconName) ? `icon-${iconName}` : consoleHandler('name-error', iconName);
};
const styles = {
fontSize: `${getSize()}px`,
...color && { color: getColor() },
...cssStyle,
};
const getAriaLabel = () => {
if (ariaLabel) {
return ariaLabel;
}
if (!ariaLabel) {
if (title && description) return `${title} ${description}`;
if (title) return title;
if (description) return description;
}
return null;
};
const getIcon = () => {
return (
<i
class={
`md-icon icon` +
` ${getNameClass()}` +
`${(className && ` ${className}`) || ''}` +
`${(prepend && ` md-prepend`) || ''}` +
`${(append && ` md-append`) || ''}`
}
aria-label={!this.$listeners.click ? getAriaLabel() : null}
style={styles}
{...!this.$listeners.click && { ...otherProps }}
/>
);
};
const button = h(
'md-button',
{
class:
'md-button--icon' +
`${(type && ` md-button--icon-${type}`) || ''}` +
`${(buttonClassName && ` ${buttonClassName}`) || ''}`,
on: {
click: this.handleClick,
},
attrs: {
'aria-label': getAriaLabel(),
...otherProps
},
},
[
getIcon(),
]
);
return (
this.$listeners.click ? button : getIcon()
)
},
props: {
/** @prop Add margin to the left of Icon | false */
append: Boolean,
/** @prop Text to display for blindness accessibility features | null */
ariaLabel: String,
/** @prop Optional Button class name string | '' */
buttonClassName: {
type: String,
default: ''
},
/** @prop Optional color css styling | '' */
color: {
type: String,
default: ''
},
/** @prop Optional class name string | '' */
className: {
type: String,
default: ''
},
/** @prop Icon description text | '' */
description: {
type: String,
default: ''
},
/** @prop Required Icon name */
name: {
type: String,
required: true
},
/** @prop Add margin to the right of Icon | null */
prepend: Boolean,
/** @prop Sets Icon size | null */
size: Number,
// Internal prop to override iconName with size prop */
sizeOverride: Boolean,
/** @prop Additional style properties to be applied | null */
cssStyle: Object,
/** @prop Sets Icon Title prop | '' */
title: {
type: String,
default: ''
},
/** @prop Sets Icon Type | '' */
type: {
type: String,
default: '',
validator: function (value) {
return ['', 'white'].indexOf(value) !== -1
}
},
},
methods: {
handleClick(e) {
this.$emit('click', e);
},
}
};
</script>
11 changes: 11 additions & 0 deletions vue/src/lib/icon/tests/__snapshots__/icon.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Icon Test the accessibilty of <md-icon /> should match SnapShot 1`] = `<i aria-label="Test Title This is a test description" class="md-icon icon icon-accessibility_16" style="font-size: 16px;"></i>`;

exports[`Icon Test the accessibilty of <md-icon /> should match SnapShot 2`] = `<i aria-label="Test Title This is a test description" class="md-icon icon icon-accessibility_16" style="font-size: 16px;"></i>`;

exports[`Icon Test the colors of <md-icon /> should match SnapShot 1`] = `<i class="md-icon icon icon-accessibility_16" style="font-size: 16px;"></i>`;

exports[`Icon Test the sizes of <md-icon /> should match SnapShot 1`] = `<i class="md-icon icon icon-accessibility_16 testClass" style="font-size: 24px; color: rgb(255, 92, 74);"></i>`;

exports[`Icon should match snapshot 1`] = `<i class="md-icon icon icon-accessibility_16 testClass" style="font-size: 16px; color: rgb(0, 160, 209);"></i>`;
Loading

0 comments on commit 59c292e

Please sign in to comment.