UNPKG

7.44 kBJavaScriptView Raw
1/*
2Copyright 2013-2015 ASIAL CORPORATION
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15
16*/
17
18import onsElements from '../ons/elements.js';
19import util from '../ons/util.js';
20import autoStyle from '../ons/autostyle.js';
21import BaseElement from './base/base-element.js';
22import contentReady from '../ons/content-ready.js';
23
24let autoPrefix = 'fa'; // FIXME: To be removed in v3
25
26/**
27 * @element ons-icon
28 * @category visual
29 * @description
30 * [en]
31 * Displays an icon. The following icon suites are available:
32 *
33 * * [Font Awesome](https://fortawesome.github.io/Font-Awesome/)
34 * * [Ionicons](http://ionicons.com/)
35 * * [Material Design Iconic Font](http://zavoloklom.github.io/material-design-iconic-font/)
36 * [/en]
37 * [ja][/ja]
38 * @codepen xAhvg
39 * @tutorial vanilla/Reference/icon
40 * @guide theming.html#cross-platform-styling-autostyling [en]Information about cross platform styling[/en][ja][/ja]
41 * @guide appsize.html#removing-icon-packs [en]Removing icon packs.[/en][ja][/ja]
42 * @guide faq.html#how-can-i-use-custom-icon-packs [en]Adding custom icon packs.[/en][ja][/ja]
43 * @example
44 * <ons-icon
45 * icon="md-car"
46 * size="20px"
47 * style="color: red">
48 * </ons-icon>
49 *
50 * <ons-button>
51 * <ons-icon icon="md-car"></ons-icon>
52 * Car
53 * </ons-button>
54 */
55export default class IconElement extends BaseElement {
56
57 /**
58 * @attribute icon
59 * @type {String}
60 * @description
61 * [en]
62 * The icon name. `"md-"` prefix for Material Icons, `"fa-"` for Font Awesome and `"ion-"` prefix for Ionicons.
63 *
64 * See all available icons on the element description (at the top).
65 *
66 * Icons can also be styled based on modifier presence. Add comma-separated icons with `"modifierName:"` prefix.
67 *
68 * The code `<ons-icon icon="ion-edit, material:md-edit"></ons-icon>` will display `"md-edit"` for Material Design and `"ion-edit"` as the default icon.
69 *
70 * `fa-` prefix is added automatically if none is provided. Check [See also](#seealso) section for more information.
71 * [/en]
72 * [ja][/ja]
73 */
74
75 /**
76 * @attribute size
77 * @type {String}
78 * @description
79 * [en]
80 * The sizes of the icon. Valid values are lg, 2x, 3x, 4x, 5x, or in the size in pixels.
81 * Icons can also be styled based on modifier presence. Add comma-separated icons with `"modifierName:"` prefix.
82 *
83 * The code:
84 *
85 * ```
86 * <ons-icon
87 * icon="ion-edit"
88 * size="32px, material:24px">
89 * </ons-icon>
90 * ```
91 *
92 * will render as a `24px` icon if the `"material"` modifier is present and `32px` otherwise.
93 * [/en]
94 * [ja][/ja]
95 */
96
97 /**
98 * @attribute rotate
99 * @type {Number}
100 * @description
101 * [en]Number of degrees to rotate the icon. Valid values are 90, 180 and 270.[/en]
102 * [ja]アイコンを回転して表示します。90, 180, 270から指定できます。[/ja]
103 */
104
105 /**
106 * @attribute fixed-width
107 * @type {Boolean}
108 * @default false
109 * @description
110 * [en]When used in a list, you want the icons to have the same width so that they align vertically by defining this attribute.[/en]
111 * [ja][/ja]
112 */
113
114 /**
115 * @property fixedWidth
116 * @type {Boolean}
117 * @default false
118 * @description
119 * [en]When used in a list, you want the icons to have the same width so that they align vertically by defining this attribute.[/en]
120 * [ja][/ja]
121 */
122
123 /**
124 * @attribute spin
125 * @description
126 * [en]Specify whether the icon should be spinning.[/en]
127 * [ja]アイコンを回転するかどうかを指定します。[/ja]
128 */
129
130 /**
131 * @property spin
132 * @type {Boolean}
133 * @description
134 * [en]Specify whether the icon should be spinning.[/en]
135 * [ja]アイコンを回転するかどうかを指定します。[/ja]
136 */
137
138 constructor() {
139 super();
140
141 contentReady(this, () => {
142 this._compile();
143 });
144 }
145
146 static get observedAttributes() {
147 return ['icon', 'size', 'modifier', 'class'];
148 }
149
150 attributeChangedCallback(name, last, current) {
151 this._cleanClassAttribute(name === 'icon' ? last : this.getAttribute('icon'), name === 'modifier' ? last : undefined);
152 this._update();
153 }
154
155 _compile() {
156 autoStyle.prepare(this);
157 this._update();
158 }
159
160 _update() {
161 const {classList, style} = this._buildClassAndStyle(this._parseAttr('icon'), this._parseAttr('size'));
162 util.extend(this.style, style);
163
164 classList.forEach(className => this.classList.add(className));
165 }
166
167 _parseAttr(attrName, modifier = this.getAttribute('modifier') || '') {
168 const attr = this.getAttribute(attrName) || attrName || '';
169 const parts = attr.split(/\s*,\s*/);
170 const def = parts[0];
171 let md = parts[1];
172 md = (md || '').split(/\s*:\s*/);
173
174 return (modifier && (RegExp(`(^|\\s+)${md[0]}($|\\s+)`, 'i').test(modifier)) ? md[1] : def) || '';
175 }
176
177 /**
178 * Remove unneeded class value.
179 */
180 _cleanClassAttribute(lastIcon, lastModifier) {
181 const { className, prefix } = this._prefixIcon(this._parseAttr(lastIcon, lastModifier));
182 const customPrefixRE = className !== prefix ? `|${prefix}$|${prefix}-` : `|${className}$` || '';
183 const re = new RegExp(`^(fa$|fa-|ion-|zmdi$|zmdi-|ons-icon--${customPrefixRE})`);
184
185 util.arrayFrom(this.classList)
186 .filter(className => re.test(className))
187 .forEach(className => this.classList.remove(className));
188 }
189
190 _prefixIcon(iconName) {
191 const className = autoPrefix + (autoPrefix ? '-' : '') + iconName;
192 return { className, prefix: className.split('-')[0] };
193 }
194
195 _buildClassAndStyle(iconName, size) {
196 const classList = ['ons-icon'];
197 const style = {};
198
199 // Icon
200 if (iconName.indexOf('ion-') === 0) {
201 classList.push(iconName);
202 classList.push('ons-icon--ion');
203 } else if (iconName.indexOf('fa-') === 0) {
204 classList.push(iconName);
205 // default icon style to Font Awesome Solid if icon style is not specified already
206 if (!(this.classList.contains('far') || this.classList.contains('fab') || this.classList.contains('fal'))) {
207 classList.push('fa');
208 }
209 } else if (iconName.indexOf('md-') === 0) {
210 classList.push('zmdi');
211 classList.push('zmdi-' + iconName.split(/-(.+)?/)[1]);
212 } else {
213 const { className, prefix } = this._prefixIcon(iconName);
214 prefix && classList.push(prefix);
215 className && classList.push(className);
216 }
217
218 // Size
219 if (size.match(/^[1-5]x|lg$/)) {
220 classList.push('ons-icon--' + size);
221 this.style.removeProperty('font-size');
222 } else {
223 style.fontSize = size;
224 }
225
226 return {
227 classList: classList,
228 style: style
229 };
230 }
231
232 static setAutoPrefix(prefix) {
233 autoPrefix = prefix ? (typeof prefix === 'string' && prefix || 'fa') : '';
234 }
235}
236
237util.defineBooleanProperties(IconElement, ['fixed-width', 'spin']);
238
239onsElements.Icon = IconElement;
240customElements.define('ons-icon', IconElement);