mirror of
https://github.com/iconify/iconify.git
synced 2025-01-06 07:20:40 +00:00
Add class names to icons loaded from API in components, matching SVG framework functionality
This commit is contained in:
parent
144604ce2b
commit
3f6265fdac
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import type { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import type {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -310,10 +310,13 @@ interface InternalIconProps extends IconProps {
|
||||
_inline: boolean;
|
||||
}
|
||||
|
||||
type IconComponentData = Required<IconifyIcon> | null;
|
||||
interface IconComponentData {
|
||||
data: Required<IconifyIcon>;
|
||||
classes?: string[];
|
||||
}
|
||||
|
||||
interface IconComponentState {
|
||||
data: IconComponentData;
|
||||
icon: IconComponentData | null;
|
||||
}
|
||||
|
||||
interface ComponentAbortData {
|
||||
@ -332,7 +335,7 @@ class IconComponent extends React.Component<
|
||||
super(props);
|
||||
this.state = {
|
||||
// Render placeholder before component is mounted
|
||||
data: null,
|
||||
icon: null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -349,10 +352,10 @@ class IconComponent extends React.Component<
|
||||
/**
|
||||
* Update state
|
||||
*/
|
||||
_setData(data: IconComponentData) {
|
||||
if (this.state.data !== data) {
|
||||
_setData(icon: IconComponentData | null) {
|
||||
if (this.state.icon !== icon) {
|
||||
this.setState({
|
||||
data,
|
||||
icon,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -374,22 +377,28 @@ class IconComponent extends React.Component<
|
||||
this._icon = '';
|
||||
this._abortLoading();
|
||||
|
||||
if (changed || state.data === null) {
|
||||
if (changed || state.icon === null) {
|
||||
// Set data if it was changed
|
||||
this._setData(fullIcon(icon));
|
||||
this._setData({
|
||||
data: fullIcon(icon),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Invalid icon?
|
||||
if (typeof icon !== 'string') {
|
||||
let iconName: IconifyIconName | null;
|
||||
if (
|
||||
typeof icon !== 'string' ||
|
||||
(iconName = stringToIcon(icon, false, true)) === null
|
||||
) {
|
||||
this._abortLoading();
|
||||
this._setData(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Load icon
|
||||
const data = getIconData(icon);
|
||||
const data = getIconData(iconName);
|
||||
if (data === null) {
|
||||
// Icon needs to be loaded
|
||||
if (!this._loading || this._loading.name !== icon) {
|
||||
@ -400,7 +409,7 @@ class IconComponent extends React.Component<
|
||||
this._loading = {
|
||||
name: icon,
|
||||
abort: API.loadIcons(
|
||||
[icon],
|
||||
[iconName],
|
||||
this._checkIcon.bind(this, false)
|
||||
),
|
||||
};
|
||||
@ -409,11 +418,25 @@ class IconComponent extends React.Component<
|
||||
}
|
||||
|
||||
// Icon data is available
|
||||
if (this._icon !== icon || state.data === null) {
|
||||
if (this._icon !== icon || state.icon === null) {
|
||||
// New icon or icon has been loaded
|
||||
this._abortLoading();
|
||||
this._icon = icon;
|
||||
this._setData(data);
|
||||
|
||||
// Add classes
|
||||
const classes: string[] = ['iconify'];
|
||||
if (iconName.prefix !== '') {
|
||||
classes.push('iconify--' + iconName.prefix);
|
||||
}
|
||||
if (iconName.provider !== '') {
|
||||
classes.push('iconify--' + iconName.provider);
|
||||
}
|
||||
|
||||
// Set data
|
||||
this._setData({
|
||||
data,
|
||||
classes,
|
||||
});
|
||||
if (this.props.onLoad) {
|
||||
this.props.onLoad(icon);
|
||||
}
|
||||
@ -448,17 +471,28 @@ class IconComponent extends React.Component<
|
||||
*/
|
||||
render() {
|
||||
const props = this.props;
|
||||
const data = this.state.data;
|
||||
const icon = this.state.icon;
|
||||
|
||||
if (data === null) {
|
||||
if (icon === null) {
|
||||
// Render placeholder
|
||||
return props.children
|
||||
? (props.children as JSX.Element)
|
||||
: React.createElement('span', {});
|
||||
}
|
||||
|
||||
// Add classes
|
||||
let newProps = props;
|
||||
if (icon.classes) {
|
||||
newProps = merge(props, {
|
||||
className:
|
||||
(typeof props.className === 'string'
|
||||
? props.className + ' '
|
||||
: '') + icon.classes.join(' '),
|
||||
} as typeof props);
|
||||
}
|
||||
|
||||
// Render icon
|
||||
return render(data, props, props._inline, props._ref);
|
||||
return render(icon.data, newProps, props._inline, props._ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -73,6 +74,7 @@ describe('Rendering icon', () => {
|
||||
'height': '1em',
|
||||
'preserveAspectRatio': 'xMidYMid meet',
|
||||
'viewBox': '0 0 ' + iconData.width + ' ' + iconData.height,
|
||||
className,
|
||||
},
|
||||
children: null,
|
||||
});
|
||||
@ -88,6 +90,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'mock-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -137,6 +140,7 @@ describe('Rendering icon', () => {
|
||||
iconData.width +
|
||||
' ' +
|
||||
iconData.height,
|
||||
'className': 'test ' + className,
|
||||
},
|
||||
children: null,
|
||||
});
|
||||
@ -157,6 +161,7 @@ describe('Rendering icon', () => {
|
||||
const component = renderer.create(
|
||||
<Icon
|
||||
icon={iconName}
|
||||
className="test"
|
||||
onLoad={(name) => {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
|
@ -23,6 +23,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
|
||||
const onLoad = (name) => {
|
||||
@ -91,6 +92,7 @@ describe('Rendering icon', () => {
|
||||
iconData.width +
|
||||
' ' +
|
||||
iconData.height,
|
||||
className,
|
||||
},
|
||||
children: null,
|
||||
});
|
||||
@ -151,6 +153,7 @@ describe('Rendering icon', () => {
|
||||
iconData2.width +
|
||||
' ' +
|
||||
iconData2.height,
|
||||
className,
|
||||
},
|
||||
children: null,
|
||||
});
|
||||
@ -190,6 +193,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let isSync = true;
|
||||
|
||||
mockAPIData({
|
||||
@ -257,6 +261,7 @@ describe('Rendering icon', () => {
|
||||
iconData2.width +
|
||||
' ' +
|
||||
iconData2.height,
|
||||
className,
|
||||
},
|
||||
children: null,
|
||||
});
|
||||
@ -292,6 +297,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'multiple-props';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
@ -336,6 +342,7 @@ describe('Rendering icon', () => {
|
||||
iconData.width +
|
||||
' ' +
|
||||
iconData.height,
|
||||
className,
|
||||
},
|
||||
children: null,
|
||||
});
|
||||
@ -371,6 +378,7 @@ describe('Rendering icon', () => {
|
||||
iconData.width +
|
||||
' ' +
|
||||
iconData.height,
|
||||
className,
|
||||
},
|
||||
children: null,
|
||||
});
|
||||
|
@ -5,8 +5,7 @@ import { mockAPIData } from '@iconify/core/lib/api/modules/mock';
|
||||
import { provider, nextPrefix } from './load';
|
||||
|
||||
const iconData = {
|
||||
body:
|
||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
||||
body: '<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
||||
width: 24,
|
||||
height: 24,
|
||||
};
|
||||
@ -16,6 +15,7 @@ describe('Testing references', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
prefix,
|
||||
|
@ -26,7 +26,12 @@
|
||||
// Generate data
|
||||
$: {
|
||||
counter;
|
||||
data = mounted ? generateIcon(checkIconState($$props.icon, state, loaded, $$props.onLoad), $$props) : null;
|
||||
const iconData = checkIconState($$props.icon, state, loaded, $$props.onLoad);
|
||||
data = mounted && iconData ? generateIcon(iconData.data, $$props) : null;
|
||||
if (data && iconData.classes) {
|
||||
// Add classes
|
||||
data.attributes['class'] = (typeof $$props['class'] === 'string' ? $$props['class'] + ' ' : '') + iconData.classes.join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Increase counter when loaded to force re-calculation of data
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import type { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import type {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -326,6 +326,14 @@ type IconStateCallback = () => void;
|
||||
*/
|
||||
export type IconifyIconOnLoad = (name: string) => void;
|
||||
|
||||
/**
|
||||
* checkIconState result
|
||||
*/
|
||||
export interface CheckIconStateResult {
|
||||
data: IconComponentData;
|
||||
classes?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if component needs to be updated
|
||||
*/
|
||||
@ -334,7 +342,7 @@ export function checkIconState(
|
||||
state: IconState,
|
||||
callback: IconStateCallback,
|
||||
onload?: IconifyIconOnLoad
|
||||
): IconComponentData {
|
||||
): CheckIconStateResult | null {
|
||||
// Abort loading icon
|
||||
function abortLoading() {
|
||||
if (state.loading) {
|
||||
@ -352,17 +360,21 @@ export function checkIconState(
|
||||
// Stop loading
|
||||
state.name = '';
|
||||
abortLoading();
|
||||
return fullIcon(icon);
|
||||
return { data: fullIcon(icon) };
|
||||
}
|
||||
|
||||
// Invalid icon
|
||||
if (typeof icon !== 'string') {
|
||||
// Invalid icon?
|
||||
let iconName: IconifyIconName | null;
|
||||
if (
|
||||
typeof icon !== 'string' ||
|
||||
(iconName = stringToIcon(icon, false, true)) === null
|
||||
) {
|
||||
abortLoading();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Load icon
|
||||
const data = getIconData(icon);
|
||||
const data = getIconData(iconName);
|
||||
if (data === null) {
|
||||
// Icon needs to be loaded
|
||||
if (!state.loading || state.loading.name !== icon) {
|
||||
@ -371,7 +383,7 @@ export function checkIconState(
|
||||
state.name = '';
|
||||
state.loading = {
|
||||
name: icon,
|
||||
abort: API.loadIcons([icon], callback),
|
||||
abort: API.loadIcons([iconName], callback),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
@ -385,7 +397,17 @@ export function checkIconState(
|
||||
onload(icon);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
|
||||
// Add classes
|
||||
const classes: string[] = ['iconify'];
|
||||
if (iconName.prefix !== '') {
|
||||
classes.push('iconify--' + iconName.prefix);
|
||||
}
|
||||
if (iconName.provider !== '') {
|
||||
classes.push('iconify--' + iconName.provider);
|
||||
}
|
||||
|
||||
return { data, classes };
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,8 +4,7 @@ import { mockAPIData } from '@iconify/core/lib/api/modules/mock';
|
||||
import { provider, nextPrefix } from './load';
|
||||
|
||||
const iconData = {
|
||||
body:
|
||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
||||
body: '<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
||||
width: 24,
|
||||
height: 24,
|
||||
};
|
||||
@ -15,6 +14,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -59,7 +59,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// Make sure onLoad has been called
|
||||
@ -73,6 +75,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'mock-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -106,7 +109,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="test ' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
@ -124,6 +129,8 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const component = render(Icon, {
|
||||
icon: iconName,
|
||||
// Also testing simple class
|
||||
class: 'test',
|
||||
onLoad: (name) => {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
|
@ -6,15 +6,13 @@ import ChangeIcon from './fixtures/ChangeIcon.svelte';
|
||||
import ChangeProps from './fixtures/ChangeProps.svelte';
|
||||
|
||||
const iconData = {
|
||||
body:
|
||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
||||
body: '<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
||||
width: 24,
|
||||
height: 24,
|
||||
};
|
||||
|
||||
const iconData2 = {
|
||||
body:
|
||||
'<path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"/>',
|
||||
body: '<path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"/>',
|
||||
width: 32,
|
||||
height: 32,
|
||||
};
|
||||
@ -26,6 +24,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
let triggerSwap;
|
||||
|
||||
@ -63,7 +62,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
@ -107,7 +108,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32" class="' +
|
||||
className +
|
||||
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called for second icon
|
||||
@ -163,6 +166,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
let isSync = true;
|
||||
let triggerSwap;
|
||||
@ -219,7 +223,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32" class="' +
|
||||
className +
|
||||
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called for second icon
|
||||
@ -269,6 +275,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'multiple-props';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
let triggerSwap;
|
||||
|
||||
@ -303,7 +310,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
@ -316,13 +325,14 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
// Check HTML again
|
||||
const node = component.container.querySelector(
|
||||
'svg'
|
||||
);
|
||||
const node =
|
||||
component.container.querySelector('svg');
|
||||
const html = node.parentNode.innerHTML;
|
||||
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
'"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||
);
|
||||
|
||||
done();
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
import { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -27,8 +27,9 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import type { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/core/lib/icon';
|
||||
import { merge } from '@iconify/core/lib/misc/merge';
|
||||
|
||||
// Modules
|
||||
import { coreModules } from '@iconify/core/lib/modules';
|
||||
@ -312,6 +313,11 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
interface IconComponentData {
|
||||
data: Required<IconifyIcon>;
|
||||
classes?: string[];
|
||||
}
|
||||
|
||||
export const Icon = defineComponent({
|
||||
// Do not inherit other attributes: it is handled by render()
|
||||
inheritAttrs: false,
|
||||
@ -350,7 +356,10 @@ export const Icon = defineComponent({
|
||||
}
|
||||
},
|
||||
// Get data for icon to render or null
|
||||
getIcon(icon: IconifyIcon | string, onload?: IconifyIconOnLoad) {
|
||||
getIcon(
|
||||
icon: IconifyIcon | string,
|
||||
onload?: IconifyIconOnLoad
|
||||
): IconComponentData | null {
|
||||
// Icon is an object
|
||||
if (
|
||||
typeof icon === 'object' &&
|
||||
@ -360,17 +369,23 @@ export const Icon = defineComponent({
|
||||
// Stop loading
|
||||
this._name = '';
|
||||
this.abortLoading();
|
||||
return fullIcon(icon);
|
||||
return {
|
||||
data: fullIcon(icon),
|
||||
};
|
||||
}
|
||||
|
||||
// Invalid icon?
|
||||
if (typeof icon !== 'string') {
|
||||
let iconName: IconifyIconName | null;
|
||||
if (
|
||||
typeof icon !== 'string' ||
|
||||
(iconName = stringToIcon(icon, false, true)) === null
|
||||
) {
|
||||
this.abortLoading();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Load icon
|
||||
const data = getIconData(icon);
|
||||
const data = getIconData(iconName);
|
||||
if (data === null) {
|
||||
// Icon needs to be loaded
|
||||
if (!this._loadingIcon || this._loadingIcon.name !== icon) {
|
||||
@ -379,7 +394,7 @@ export const Icon = defineComponent({
|
||||
this._name = '';
|
||||
this._loadingIcon = {
|
||||
name: icon,
|
||||
abort: API.loadIcons([icon], () => {
|
||||
abort: API.loadIcons([iconName], () => {
|
||||
this.counter++;
|
||||
}),
|
||||
};
|
||||
@ -395,7 +410,17 @@ export const Icon = defineComponent({
|
||||
onload(icon);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
|
||||
// Add classes
|
||||
const classes: string[] = ['iconify'];
|
||||
if (iconName.prefix !== '') {
|
||||
classes.push('iconify--' + iconName.prefix);
|
||||
}
|
||||
if (iconName.provider !== '') {
|
||||
classes.push('iconify--' + iconName.provider);
|
||||
}
|
||||
|
||||
return { data, classes };
|
||||
},
|
||||
},
|
||||
|
||||
@ -410,14 +435,28 @@ export const Icon = defineComponent({
|
||||
|
||||
// Get icon data
|
||||
const props = this.$attrs;
|
||||
const icon = this.getIcon(props.icon, props.onLoad);
|
||||
const icon: IconComponentData | null = this.getIcon(
|
||||
props.icon,
|
||||
props.onLoad
|
||||
);
|
||||
|
||||
// Validate icon object
|
||||
if (!icon) {
|
||||
return this.$slots.default ? this.$slots.default() : null;
|
||||
}
|
||||
|
||||
// Valid icon: render it
|
||||
return render(icon, props);
|
||||
// Add classes
|
||||
let newProps = props;
|
||||
if (icon.classes) {
|
||||
newProps = merge(props, {
|
||||
class:
|
||||
(typeof props['class'] === 'string'
|
||||
? props['class'] + ' '
|
||||
: '') + icon.classes.join(' '),
|
||||
});
|
||||
}
|
||||
|
||||
// Render icon
|
||||
return render(icon.data, newProps);
|
||||
},
|
||||
});
|
||||
|
@ -15,6 +15,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -48,7 +49,8 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
// Also test class string
|
||||
template: `<Icon icon="${iconName}" :onLoad="onLoad" class="test" />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
@ -62,7 +64,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="test ' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// Make sure onLoad has been called
|
||||
@ -76,6 +80,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'mock-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -106,7 +111,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
// Check HTML
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="foo ' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
@ -124,7 +131,7 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad="onLoad" :class="testClass" />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
@ -132,6 +139,15 @@ describe('Rendering icon', () => {
|
||||
onLoadCalled = true;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
// Test dynamic class
|
||||
return {
|
||||
testClass: {
|
||||
foo: true,
|
||||
bar: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
|
||||
|
@ -24,6 +24,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
|
||||
const onLoad = name => {
|
||||
@ -72,7 +73,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
@ -113,7 +116,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called for second icon
|
||||
@ -151,6 +156,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let isSync = true;
|
||||
|
||||
mockAPIData({
|
||||
@ -198,7 +204,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
done();
|
||||
@ -234,6 +242,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'multiple-props';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
@ -259,7 +268,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// Add horizontal flip and style
|
||||
@ -276,7 +287,9 @@ describe('Rendering icon', () => {
|
||||
expect(
|
||||
wrapper.html().replace(/\s*\n\s*/g, '')
|
||||
).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="' +
|
||||
className +
|
||||
'" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||
);
|
||||
|
||||
done();
|
||||
|
@ -3,7 +3,7 @@ import { ExtendedVue } from 'vue/types/vue';
|
||||
import { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -19,8 +19,9 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import type { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/core/lib/icon';
|
||||
import { merge } from '@iconify/core/lib/misc/merge';
|
||||
|
||||
// Modules
|
||||
import { coreModules } from '@iconify/core/lib/modules';
|
||||
@ -304,6 +305,11 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
interface IconComponentData {
|
||||
data: Required<IconifyIcon>;
|
||||
classes?: string[];
|
||||
}
|
||||
|
||||
export const Icon = Vue.extend({
|
||||
// Do not inherit other attributes: it is handled by render()
|
||||
// In Vue 2 style is still passed!
|
||||
@ -340,7 +346,10 @@ export const Icon = Vue.extend({
|
||||
}
|
||||
},
|
||||
// Get data for icon to render or null
|
||||
getIcon(icon: IconifyIcon | string, onload?: IconifyIconOnLoad) {
|
||||
getIcon(
|
||||
icon: IconifyIcon | string,
|
||||
onload?: IconifyIconOnLoad
|
||||
): IconComponentData | null {
|
||||
// Icon is an object
|
||||
if (
|
||||
typeof icon === 'object' &&
|
||||
@ -350,17 +359,23 @@ export const Icon = Vue.extend({
|
||||
// Stop loading
|
||||
this._name = '';
|
||||
this.abortLoading();
|
||||
return fullIcon(icon);
|
||||
return {
|
||||
data: fullIcon(icon),
|
||||
};
|
||||
}
|
||||
|
||||
// Invalid icon?
|
||||
if (typeof icon !== 'string') {
|
||||
let iconName: IconifyIconName | null;
|
||||
if (
|
||||
typeof icon !== 'string' ||
|
||||
(iconName = stringToIcon(icon, false, true)) === null
|
||||
) {
|
||||
this.abortLoading();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Load icon
|
||||
const data = getIconData(icon);
|
||||
const data = getIconData(iconName);
|
||||
if (data === null) {
|
||||
// Icon needs to be loaded
|
||||
if (!this._loadingIcon || this._loadingIcon.name !== icon) {
|
||||
@ -369,7 +384,7 @@ export const Icon = Vue.extend({
|
||||
this._name = '';
|
||||
this._loadingIcon = {
|
||||
name: icon,
|
||||
abort: API.loadIcons([icon], () => {
|
||||
abort: API.loadIcons([iconName], () => {
|
||||
this.$forceUpdate();
|
||||
}),
|
||||
};
|
||||
@ -385,7 +400,17 @@ export const Icon = Vue.extend({
|
||||
onload(icon);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
|
||||
// Add classes
|
||||
const classes: string[] = ['iconify'];
|
||||
if (iconName.prefix !== '') {
|
||||
classes.push('iconify--' + iconName.prefix);
|
||||
}
|
||||
if (iconName.provider !== '') {
|
||||
classes.push('iconify--' + iconName.provider);
|
||||
}
|
||||
|
||||
return { data, classes };
|
||||
},
|
||||
},
|
||||
|
||||
@ -410,7 +435,10 @@ export const Icon = Vue.extend({
|
||||
|
||||
// Get icon data
|
||||
const props = this.$attrs;
|
||||
const icon = this.getIcon(props.icon, props.onLoad);
|
||||
const icon: IconComponentData | null = this.getIcon(
|
||||
props.icon,
|
||||
props.onLoad
|
||||
);
|
||||
|
||||
// Validate icon object
|
||||
if (!icon) {
|
||||
@ -418,7 +446,18 @@ export const Icon = Vue.extend({
|
||||
return placeholder(this.$slots);
|
||||
}
|
||||
|
||||
// Valid icon: render it
|
||||
return render(createElement, props, this.$data, icon);
|
||||
// Add classes
|
||||
let context = this.$data;
|
||||
if (icon.classes) {
|
||||
context = merge(context, {
|
||||
class:
|
||||
(typeof context['class'] === 'string'
|
||||
? context['class'] + ' '
|
||||
: '') + icon.classes.join(' '),
|
||||
});
|
||||
}
|
||||
|
||||
// Render icon
|
||||
return render(createElement, props, context, icon.data);
|
||||
},
|
||||
});
|
||||
|
@ -14,6 +14,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -47,7 +48,8 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
// Also test class string
|
||||
template: `<Icon icon="${iconName}" :onLoad="onLoad" class="test" />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
@ -61,7 +63,9 @@ describe('Rendering icon', () => {
|
||||
|
||||
// Check HTML
|
||||
expect(html).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="test ' +
|
||||
className +
|
||||
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// Make sure onLoad has been called
|
||||
@ -75,6 +79,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'mock-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
@ -105,7 +110,10 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
// Check HTML
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
// 'foo' is appended because of weird Vue 2 behavior. Fixed in Vue 3
|
||||
' foo"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
@ -123,7 +131,7 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad="onLoad" :class="testClass" />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
@ -131,6 +139,15 @@ describe('Rendering icon', () => {
|
||||
onLoadCalled = true;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
// Test dynamic class
|
||||
return {
|
||||
testClass: {
|
||||
foo: true,
|
||||
bar: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
|
||||
@ -177,7 +194,7 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
|
||||
methods: {
|
||||
onLoad() {
|
||||
throw new Error('onLoad called for empty icon!');
|
||||
|
@ -22,6 +22,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
|
||||
const onLoad = (name) => {
|
||||
@ -70,7 +71,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
@ -111,7 +114,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32" class="' +
|
||||
className +
|
||||
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// onLoad should have been called for second icon
|
||||
@ -147,6 +152,7 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
let isSync = true;
|
||||
|
||||
mockAPIData({
|
||||
@ -194,7 +200,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32" class="' +
|
||||
className +
|
||||
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
done();
|
||||
@ -229,6 +237,7 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'multiple-props';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const className = `iconify iconify--${prefix} iconify--${provider}`;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
@ -254,7 +263,9 @@ describe('Rendering icon', () => {
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
|
||||
);
|
||||
|
||||
// Add horizontal flip and style
|
||||
@ -271,7 +282,9 @@ describe('Rendering icon', () => {
|
||||
expect(
|
||||
wrapper.html().replace(/\s*\n\s*/g, '')
|
||||
).toEqual(
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24" class="' +
|
||||
className +
|
||||
'" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||
);
|
||||
|
||||
done();
|
||||
|
Loading…
Reference in New Issue
Block a user