mirror of
https://github.com/iconify/iconify.git
synced 2025-01-06 07:20:40 +00:00
Add onLoad callback to components, export buildIcon, add onLoad event to components, fix customisations, publish new versions
This commit is contained in:
parent
46ae993b95
commit
144604ce2b
4
packages/core/package-lock.json
generated
4
packages/core/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@iconify/core",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@iconify/core",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"license": "(Apache-2.0 OR GPL-2.0)",
|
||||
"dependencies": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/core",
|
||||
"description": "Reusable files used by multiple Iconify packages",
|
||||
"author": "Vjacheslav Trushkin <cyberalien@gmail.com> (https://iconify.design)",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"license": "(Apache-2.0 OR GPL-2.0)",
|
||||
"bugs": "https://github.com/iconify/iconify/issues",
|
||||
"homepage": "https://iconify.design/",
|
||||
|
@ -21,13 +21,13 @@ Iconify SVG framework is designed to be as easy to use as possible.
|
||||
Add this line to your page to load Iconify SVG framework (you can add it to `<head>` section of the page or before `</body>`):
|
||||
|
||||
```html
|
||||
<script src="https://code.iconify.design/2/2.0.0/iconify.min.js"></script>
|
||||
<script src="https://code.iconify.design/2/2.0.1/iconify.min.js"></script>
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/@iconify/iconify@2.0.0/dist/iconify.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@iconify/iconify@2.0.1/dist/iconify.min.js"></script>
|
||||
```
|
||||
|
||||
or, if you are building a project with something like WebPack or Rollup, you can include the script by installing `@iconify/iconify` as a dependency and importing it in your project:
|
||||
|
18
packages/iconify/package-lock.json
generated
18
packages/iconify/package-lock.json
generated
@ -1,18 +1,18 @@
|
||||
{
|
||||
"name": "@iconify/iconify",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@iconify/iconify",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"license": "(Apache-2.0 OR GPL-2.0)",
|
||||
"dependencies": {
|
||||
"cross-fetch": "^3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.12.0",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
@ -62,9 +62,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
@ -2180,9 +2180,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/iconify",
|
||||
"description": "Unified SVG framework with over 70,000 icons to choose from",
|
||||
"author": "Vjacheslav Trushkin <cyberalien@gmail.com> (https://iconify.design)",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"license": "(Apache-2.0 OR GPL-2.0)",
|
||||
"main": "./dist/iconify.min.js",
|
||||
"types": "./dist/iconify.d.ts",
|
||||
@ -29,7 +29,7 @@
|
||||
"cross-fetch": "^3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.12.0",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
|
@ -2,7 +2,8 @@ import { IconifyJSON } from '@iconify/types';
|
||||
import { stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import {
|
||||
IconifyIconCustomisations,
|
||||
fullCustomisations,
|
||||
defaults,
|
||||
mergeCustomisations,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
import {
|
||||
storageFunctions,
|
||||
@ -39,7 +40,7 @@ function buildIcon(
|
||||
}
|
||||
|
||||
// Clean up customisations
|
||||
const changes = fullCustomisations(customisations);
|
||||
const changes = mergeCustomisations(defaults, customisations);
|
||||
|
||||
// Get data
|
||||
return iconToSVG(iconData, changes);
|
||||
@ -63,17 +64,17 @@ function generateIcon(
|
||||
const iconName = stringToIcon(name);
|
||||
|
||||
// Clean up customisations
|
||||
const changes = fullCustomisations(customisations);
|
||||
const changes = mergeCustomisations(defaults, customisations);
|
||||
|
||||
// Get data
|
||||
return (renderIcon(
|
||||
return renderIcon(
|
||||
{
|
||||
name: iconName,
|
||||
},
|
||||
changes,
|
||||
iconData,
|
||||
returnString
|
||||
) as unknown) as SVGElement | string | null;
|
||||
) as unknown as SVGElement | string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,10 +218,10 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
IconifyPreload: IconifyJSON[] | IconifyJSON;
|
||||
}
|
||||
if (
|
||||
((_window as unknown) as WindowWithIconifyPreload).IconifyPreload !==
|
||||
(_window as unknown as WindowWithIconifyPreload).IconifyPreload !==
|
||||
void 0
|
||||
) {
|
||||
const preload = ((_window as unknown) as WindowWithIconifyPreload)
|
||||
const preload = (_window as unknown as WindowWithIconifyPreload)
|
||||
.IconifyPreload;
|
||||
const err = 'Invalid IconifyPreload syntax.';
|
||||
if (typeof preload === 'object' && preload !== null) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { FullIconifyIcon } from '@iconify/core/lib/icon';
|
||||
import {
|
||||
IconifyIconCustomisations,
|
||||
fullCustomisations,
|
||||
mergeCustomisations,
|
||||
defaults,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||
import { replaceIDs } from '@iconify/core/lib/builder/ids';
|
||||
@ -30,7 +31,10 @@ export function renderIcon(
|
||||
return returnString ? '' : null;
|
||||
}
|
||||
|
||||
const data = iconToSVG(iconData, fullCustomisations(customisations));
|
||||
const data = iconToSVG(
|
||||
iconData,
|
||||
mergeCustomisations(defaults, customisations)
|
||||
);
|
||||
|
||||
// Placeholder properties
|
||||
const placeholderElement = placeholder.element;
|
||||
|
18
packages/react/package-lock.json
generated
18
packages/react/package-lock.json
generated
@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@iconify/react",
|
||||
"version": "3.0.0-alpha.0",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@iconify/react",
|
||||
"version": "3.0.0-alpha.0",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.13.15",
|
||||
"@babel/preset-react": "^7.13.13",
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.13.5",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
@ -1381,9 +1381,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
@ -10661,9 +10661,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/react",
|
||||
"description": "Iconify icon component for React.",
|
||||
"author": "Vjacheslav Trushkin",
|
||||
"version": "3.0.0-alpha.0",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"license": "MIT",
|
||||
"bugs": "https://github.com/iconify/iconify/issues",
|
||||
"homepage": "https://iconify.design/",
|
||||
@ -26,7 +26,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.13.15",
|
||||
"@babel/preset-react": "^7.13.13",
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.13.5",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import type { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/core/lib/icon';
|
||||
|
||||
// Modules
|
||||
@ -65,6 +66,8 @@ import type {
|
||||
|
||||
// Properties
|
||||
import type {
|
||||
RawIconCustomisations,
|
||||
IconifyIconOnLoad,
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconProps,
|
||||
IconProps,
|
||||
@ -90,7 +93,7 @@ export {
|
||||
// JSON stuff
|
||||
export { IconifyIcon, IconifyJSON, IconifyIconName };
|
||||
|
||||
// Customisations
|
||||
// Customisations and icon props
|
||||
export {
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconSize,
|
||||
@ -98,6 +101,7 @@ export {
|
||||
IconifyVerticalIconAlignment,
|
||||
IconifyIconProps,
|
||||
IconProps,
|
||||
IconifyIconOnLoad,
|
||||
};
|
||||
|
||||
// API
|
||||
@ -113,6 +117,9 @@ export {
|
||||
PartialIconifyAPIConfig,
|
||||
};
|
||||
|
||||
// Builder functions
|
||||
export { RawIconCustomisations, IconifyIconBuildResult };
|
||||
|
||||
/* Browser cache */
|
||||
export { IconifyBrowserCacheType };
|
||||
|
||||
@ -162,6 +169,11 @@ export const calculateSize = builderFunctions.calculateSize;
|
||||
*/
|
||||
export const replaceIDs = builderFunctions.replaceIDs;
|
||||
|
||||
/**
|
||||
* Build SVG
|
||||
*/
|
||||
export const buildIcon = builderFunctions.buildIcon;
|
||||
|
||||
/* API functions */
|
||||
/**
|
||||
* Load icons
|
||||
@ -228,10 +240,10 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
IconifyPreload: IconifyJSON[] | IconifyJSON;
|
||||
}
|
||||
if (
|
||||
((_window as unknown) as WindowWithIconifyPreload).IconifyPreload !==
|
||||
(_window as unknown as WindowWithIconifyPreload).IconifyPreload !==
|
||||
void 0
|
||||
) {
|
||||
const preload = ((_window as unknown) as WindowWithIconifyPreload)
|
||||
const preload = (_window as unknown as WindowWithIconifyPreload)
|
||||
.IconifyPreload;
|
||||
const err = 'Invalid IconifyPreload syntax.';
|
||||
if (typeof preload === 'object' && preload !== null) {
|
||||
@ -262,10 +274,10 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
IconifyProviders: Record<string, PartialIconifyAPIConfig>;
|
||||
}
|
||||
if (
|
||||
((_window as unknown) as WindowWithIconifyProviders)
|
||||
.IconifyProviders !== void 0
|
||||
(_window as unknown as WindowWithIconifyProviders).IconifyProviders !==
|
||||
void 0
|
||||
) {
|
||||
const providers = ((_window as unknown) as WindowWithIconifyProviders)
|
||||
const providers = (_window as unknown as WindowWithIconifyProviders)
|
||||
.IconifyProviders;
|
||||
if (typeof providers === 'object' && providers !== null) {
|
||||
for (let key in providers) {
|
||||
@ -402,6 +414,9 @@ class IconComponent extends React.Component<
|
||||
this._abortLoading();
|
||||
this._icon = icon;
|
||||
this._setData(data);
|
||||
if (this.props.onLoad) {
|
||||
this.props.onLoad(icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,22 @@
|
||||
import type { HTMLProps, RefObject } from 'react';
|
||||
import type { IconifyIcon } from '@iconify/types';
|
||||
import type { IconifyIconCustomisations as IconCustomisations } from '@iconify/core/lib/customisations';
|
||||
import type { IconifyIconCustomisations as RawIconCustomisations } from '@iconify/core/lib/customisations';
|
||||
|
||||
export { RawIconCustomisations };
|
||||
|
||||
// Allow rotation to be string
|
||||
/**
|
||||
* Icon customisations
|
||||
*/
|
||||
export type IconifyIconCustomisations = IconCustomisations & {
|
||||
export type IconifyIconCustomisations = RawIconCustomisations & {
|
||||
rotate?: string | number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for when icon has been loaded (only triggered for icons loaded from API)
|
||||
*/
|
||||
export type IconifyIconOnLoad = (name: string) => void;
|
||||
|
||||
/**
|
||||
* Icon properties
|
||||
*/
|
||||
@ -26,6 +33,9 @@ export interface IconifyIconProps extends IconifyIconCustomisations {
|
||||
|
||||
// Unique id, used as base for ids for shapes. Use it to get consistent ids for server side rendering
|
||||
id?: string;
|
||||
|
||||
// Callback to call when icon data has been loaded. Used only for icons loaded from API
|
||||
onLoad?: IconifyIconOnLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,7 +2,10 @@ import type { SVGProps } from 'react';
|
||||
import React from 'react';
|
||||
import type { IconifyIcon } from '@iconify/types';
|
||||
import type { FullIconCustomisations } from '@iconify/core/lib/customisations';
|
||||
import { defaults } from '@iconify/core/lib/customisations';
|
||||
import {
|
||||
defaults,
|
||||
mergeCustomisations,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
import {
|
||||
flipFromString,
|
||||
alignmentFromString,
|
||||
@ -51,7 +54,7 @@ export const render = (
|
||||
const defaultProps = inline ? inlineDefaults : defaults;
|
||||
|
||||
// Get all customisations
|
||||
const customisations = merge(
|
||||
const customisations = mergeCustomisations(
|
||||
defaultProps,
|
||||
props as IconifyIconCustomisations
|
||||
) as FullIconCustomisations;
|
||||
@ -71,15 +74,27 @@ export const render = (
|
||||
// Get element properties
|
||||
for (let key in props) {
|
||||
const value = props[key];
|
||||
if (value === void 0) {
|
||||
continue;
|
||||
}
|
||||
switch (key) {
|
||||
// Properties to ignore
|
||||
case 'icon':
|
||||
case 'style':
|
||||
case 'children':
|
||||
case 'onLoad':
|
||||
case '_ref':
|
||||
case '_inline':
|
||||
break;
|
||||
|
||||
// Boolean attributes
|
||||
case 'inline':
|
||||
case 'hFlip':
|
||||
case 'vFlip':
|
||||
customisations[key] =
|
||||
value === true || value === 'true' || value === 1;
|
||||
break;
|
||||
|
||||
// Flip as string: 'horizontal,vertical'
|
||||
case 'flip':
|
||||
if (typeof value === 'string') {
|
||||
|
@ -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,8 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
prefix,
|
||||
@ -45,7 +46,16 @@ describe('Rendering icon', () => {
|
||||
expect(iconExists(iconName)).toEqual(true);
|
||||
|
||||
// Render component
|
||||
const component = renderer.create(<Icon icon={iconName} />);
|
||||
const component = renderer.create(
|
||||
<Icon
|
||||
icon={iconName}
|
||||
onLoad={(name) => {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
onLoadCalled = true;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchObject({
|
||||
@ -67,6 +77,9 @@ describe('Rendering icon', () => {
|
||||
children: null,
|
||||
});
|
||||
|
||||
// Make sure onLoad has been called
|
||||
expect(onLoadCalled).toEqual(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -75,6 +88,8 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'mock-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
prefix,
|
||||
@ -88,6 +103,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -123,6 +141,9 @@ describe('Rendering icon', () => {
|
||||
children: null,
|
||||
});
|
||||
|
||||
// onLoad should have been called
|
||||
expect(onLoadCalled).toEqual(true);
|
||||
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
@ -133,7 +154,16 @@ describe('Rendering icon', () => {
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// Render component
|
||||
const component = renderer.create(<Icon icon={iconName} />);
|
||||
const component = renderer.create(
|
||||
<Icon
|
||||
icon={iconName}
|
||||
onLoad={(name) => {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
onLoadCalled = true;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
// Should render placeholder
|
||||
@ -142,6 +172,9 @@ describe('Rendering icon', () => {
|
||||
props: {},
|
||||
children: null,
|
||||
});
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
});
|
||||
|
||||
test('missing icon', (done) => {
|
||||
@ -184,7 +217,14 @@ describe('Rendering icon', () => {
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// Render component
|
||||
const component = renderer.create(<Icon icon={iconName}></Icon>);
|
||||
const component = renderer.create(
|
||||
<Icon
|
||||
icon={iconName}
|
||||
onLoad={() => {
|
||||
throw new Error('onLoad called for empty icon!');
|
||||
}}
|
||||
></Icon>
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
// Should render placeholder
|
||||
|
@ -5,15 +5,13 @@ 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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
@ -25,6 +23,26 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
|
||||
const onLoad = (name) => {
|
||||
// onLoad should be called only once per icon
|
||||
switch (name) {
|
||||
// First onLoad call
|
||||
case iconName:
|
||||
expect(onLoadCalled).toEqual('');
|
||||
break;
|
||||
|
||||
// Second onLoad call
|
||||
case iconName2:
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unexpected onLoad('${name}') call`);
|
||||
}
|
||||
onLoadCalled = name;
|
||||
};
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
@ -39,6 +57,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual('');
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -74,7 +95,13 @@ describe('Rendering icon', () => {
|
||||
children: null,
|
||||
});
|
||||
|
||||
component.update(<Icon icon={iconName2} />);
|
||||
// onLoad should have been called
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
|
||||
// Change property
|
||||
component.update(
|
||||
<Icon icon={iconName2} onLoad={onLoad} />
|
||||
);
|
||||
}, 0);
|
||||
}, 0);
|
||||
},
|
||||
@ -128,6 +155,9 @@ describe('Rendering icon', () => {
|
||||
children: null,
|
||||
});
|
||||
|
||||
// onLoad should have been called for second icon
|
||||
expect(onLoadCalled).toEqual(iconName2);
|
||||
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
@ -138,7 +168,9 @@ describe('Rendering icon', () => {
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// Render component
|
||||
const component = renderer.create(<Icon icon={iconName} />);
|
||||
const component = renderer.create(
|
||||
<Icon icon={iconName} onLoad={onLoad} />
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
// Should render placeholder
|
||||
@ -147,6 +179,9 @@ describe('Rendering icon', () => {
|
||||
props: {},
|
||||
children: null,
|
||||
});
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual('');
|
||||
});
|
||||
|
||||
test('changing icon property while loading', (done) => {
|
||||
|
@ -3,15 +3,22 @@ import { Icon, InlineIcon } from '../../dist/iconify';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
describe('Creating component using object', () => {
|
||||
test('basic icon', () => {
|
||||
const component = renderer.create(<Icon icon={iconData} />);
|
||||
const component = renderer.create(
|
||||
<Icon
|
||||
icon={iconData}
|
||||
onLoad={() => {
|
||||
// Should be called only for icons loaded from API
|
||||
throw new Error('onLoad called for object!');
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree).toMatchObject({
|
||||
|
@ -3,8 +3,7 @@ import { Icon } from '../../dist/iconify';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -20,12 +19,12 @@ describe('Inline attribute', () => {
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const component = renderer.create(
|
||||
<Icon icon={iconData} inline="false" />
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree.props.style.verticalAlign).toStrictEqual('-0.125em');
|
||||
expect(tree.props.style.verticalAlign).toEqual(void 0);
|
||||
});
|
||||
});
|
||||
|
@ -3,8 +3,7 @@ import { InlineIcon } from '../../dist/iconify';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -80,9 +79,9 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const component = renderer.create(
|
||||
<InlineIcon icon={iconData} flip="horizontal" hFlip={false} />
|
||||
<InlineIcon icon={iconData} hFlip={false} flip="horizontal" />
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
const body = tree.props.dangerouslySetInnerHTML.__html;
|
||||
|
@ -3,13 +3,21 @@ import { Icon } from '../../dist/offline';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
describe('Inline attribute', () => {
|
||||
test('boolean true', () => {
|
||||
const component = renderer.create(
|
||||
<Icon icon={iconData} inline={true} />
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree.props.style.verticalAlign).toStrictEqual('-0.125em');
|
||||
});
|
||||
|
||||
test('string', () => {
|
||||
const component = renderer.create(
|
||||
<Icon icon={iconData} inline="true" />
|
||||
@ -19,13 +27,22 @@ describe('Inline attribute', () => {
|
||||
expect(tree.props.style.verticalAlign).toStrictEqual('-0.125em');
|
||||
});
|
||||
|
||||
test('false', () => {
|
||||
const component = renderer.create(
|
||||
<Icon icon={iconData} inline={false} />
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree.props.style.verticalAlign).toEqual(void 0);
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const component = renderer.create(
|
||||
<Icon icon={iconData} inline="false" />
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
|
||||
expect(tree.props.style.verticalAlign).toStrictEqual('-0.125em');
|
||||
expect(tree.props.style.verticalAlign).toEqual(void 0);
|
||||
});
|
||||
});
|
||||
|
@ -3,8 +3,7 @@ import { InlineIcon } from '../../dist/offline';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
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: 32,
|
||||
};
|
||||
@ -80,9 +79,9 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const component = renderer.create(
|
||||
<InlineIcon icon={iconData} flip="horizontal" hFlip={false} />
|
||||
<InlineIcon icon={iconData} hFlip={false} flip="horizontal" />
|
||||
);
|
||||
const tree = component.toJSON();
|
||||
const body = tree.props.dangerouslySetInnerHTML.__html;
|
||||
|
@ -1,7 +1,9 @@
|
||||
.DS_Store
|
||||
rollup.config.js
|
||||
tsconfig.json
|
||||
api-extractor*.json
|
||||
build.js
|
||||
copy.js
|
||||
node_modules
|
||||
build
|
||||
src
|
||||
|
18
packages/svelte/package-lock.json
generated
18
packages/svelte/package-lock.json
generated
@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@iconify/svelte",
|
||||
"version": "2.0.0-alpha.4",
|
||||
"version": "2.0.0-alpha.6",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@iconify/svelte",
|
||||
"version": "2.0.0-alpha.4",
|
||||
"version": "2.0.0-alpha.6",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.14.0",
|
||||
"@iconify/core": "^1.0.0-rc.3",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.15.0",
|
||||
"@rollup/plugin-commonjs": "^16.0.0",
|
||||
@ -1484,9 +1484,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
@ -9800,9 +9800,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/svelte",
|
||||
"description": "Iconify icon component for Svelte.",
|
||||
"author": "Vjacheslav Trushkin",
|
||||
"version": "2.0.0-alpha.4",
|
||||
"version": "2.0.0-alpha.6",
|
||||
"license": "MIT",
|
||||
"bugs": "https://github.com/iconify/iconify/issues",
|
||||
"homepage": "https://github.com/iconify/iconify",
|
||||
@ -27,7 +27,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.14.0",
|
||||
"@iconify/core": "^1.0.0-rc.3",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.15.0",
|
||||
"@rollup/plugin-commonjs": "^16.0.0",
|
||||
|
@ -236,10 +236,10 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
IconifyPreload: IconifyJSON[] | IconifyJSON;
|
||||
}
|
||||
if (
|
||||
((_window as unknown) as WindowWithIconifyPreload).IconifyPreload !==
|
||||
(_window as unknown as WindowWithIconifyPreload).IconifyPreload !==
|
||||
void 0
|
||||
) {
|
||||
const preload = ((_window as unknown) as WindowWithIconifyPreload)
|
||||
const preload = (_window as unknown as WindowWithIconifyPreload)
|
||||
.IconifyPreload;
|
||||
const err = 'Invalid IconifyPreload syntax.';
|
||||
if (typeof preload === 'object' && preload !== null) {
|
||||
@ -270,10 +270,10 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
IconifyProviders: Record<string, PartialIconifyAPIConfig>;
|
||||
}
|
||||
if (
|
||||
((_window as unknown) as WindowWithIconifyProviders)
|
||||
.IconifyProviders !== void 0
|
||||
(_window as unknown as WindowWithIconifyProviders).IconifyProviders !==
|
||||
void 0
|
||||
) {
|
||||
const providers = ((_window as unknown) as WindowWithIconifyProviders)
|
||||
const providers = (_window as unknown as WindowWithIconifyProviders)
|
||||
.IconifyProviders;
|
||||
if (typeof providers === 'object' && providers !== null) {
|
||||
for (let key in providers) {
|
||||
@ -378,13 +378,13 @@ export function checkIconState(
|
||||
}
|
||||
|
||||
// Icon data is available
|
||||
abortLoading();
|
||||
if (state.name !== icon) {
|
||||
state.name = icon;
|
||||
if (onload && !state.destroyed) {
|
||||
onload(icon);
|
||||
}
|
||||
}
|
||||
abortLoading();
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,50 @@
|
||||
// Types
|
||||
export type { IconifyJSON } from '@iconify/types';
|
||||
export type { IconifyIcon } from '@iconify/core/lib/icon';
|
||||
export type {
|
||||
/**
|
||||
* Export required types
|
||||
*/
|
||||
// Function sets
|
||||
export {
|
||||
IconifyStorageFunctions,
|
||||
IconifyBuilderFunctions,
|
||||
IconifyBrowserCacheFunctions,
|
||||
IconifyAPIFunctions,
|
||||
IconifyAPIInternalFunctions,
|
||||
} from './functions';
|
||||
|
||||
// JSON stuff
|
||||
export { IconifyIcon, IconifyJSON, IconifyIconName } from './functions';
|
||||
|
||||
// Customisations
|
||||
export {
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
IconifyVerticalIconAlignment,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
IconifyIconProps,
|
||||
IconProps,
|
||||
} from './functions';
|
||||
|
||||
// Types from props.ts
|
||||
export type { IconifyIconCustomisations, IconProps } from './props';
|
||||
// API
|
||||
export {
|
||||
IconifyAPIConfig,
|
||||
IconifyIconLoaderCallback,
|
||||
IconifyIconLoaderAbort,
|
||||
IconifyAPIInternalStorage,
|
||||
IconifyAPIModule,
|
||||
GetAPIConfig,
|
||||
IconifyAPIPrepareQuery,
|
||||
IconifyAPISendQuery,
|
||||
PartialIconifyAPIConfig,
|
||||
} from './functions';
|
||||
|
||||
// Component
|
||||
// Builder functions
|
||||
export { RawIconCustomisations, IconifyIconBuildResult } from './functions';
|
||||
|
||||
// Browser cache
|
||||
export { IconifyBrowserCacheType } from './functions';
|
||||
|
||||
// Component and params
|
||||
export { default as Icon } from './Icon.svelte';
|
||||
export { IconifyIconOnLoad } from './functions';
|
||||
|
||||
// Functions
|
||||
export { enableCache, disableCache } from './functions';
|
||||
|
@ -1,5 +1,8 @@
|
||||
import type { IconifyIcon } from '@iconify/types';
|
||||
import { defaults } from '@iconify/core/lib/customisations';
|
||||
import {
|
||||
defaults,
|
||||
mergeCustomisations,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
import {
|
||||
flipFromString,
|
||||
alignmentFromString,
|
||||
@ -37,7 +40,10 @@ export function render(
|
||||
// Properties
|
||||
props: IconProps
|
||||
): RenderResult {
|
||||
const customisations = merge(defaults, props as typeof defaults);
|
||||
const customisations = mergeCustomisations(
|
||||
defaults,
|
||||
props as typeof defaults
|
||||
);
|
||||
const componentProps = merge(svgDefaults) as Record<string, unknown>;
|
||||
|
||||
// Create style if missing
|
||||
@ -46,6 +52,9 @@ export function render(
|
||||
// Get element properties
|
||||
for (let key in props) {
|
||||
const value = props[key as keyof typeof props] as unknown;
|
||||
if (value === void 0) {
|
||||
continue;
|
||||
}
|
||||
switch (key) {
|
||||
// Properties to ignore
|
||||
case 'icon':
|
||||
@ -53,6 +62,14 @@ export function render(
|
||||
case 'onLoad':
|
||||
break;
|
||||
|
||||
// Boolean attributes
|
||||
case 'inline':
|
||||
case 'hFlip':
|
||||
case 'vFlip':
|
||||
customisations[key] =
|
||||
value === true || value === 'true' || value === 1;
|
||||
break;
|
||||
|
||||
// Flip as string: 'horizontal,vertical'
|
||||
case 'flip':
|
||||
if (typeof value === 'string') {
|
||||
|
@ -37,4 +37,15 @@ describe('Dimensions', () => {
|
||||
expect(node.getAttribute('height')).toEqual('24');
|
||||
expect(node.getAttribute('width')).toEqual('24');
|
||||
});
|
||||
|
||||
test('invalid values', () => {
|
||||
const component = render(Icon, {
|
||||
icon: iconData,
|
||||
height: null,
|
||||
width: void 0,
|
||||
});
|
||||
const node = component.container.querySelector('svg');
|
||||
expect(node.getAttribute('height')).toEqual('1em');
|
||||
expect(node.getAttribute('width')).toEqual('1em');
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,7 @@ import { render } from '@testing-library/svelte';
|
||||
import { Icon } from '../../dist/iconify';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -34,11 +33,11 @@ describe('Inline attribute', () => {
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const component = render(Icon, { icon: iconData, inline: 'false' });
|
||||
const node = component.container.querySelector('svg');
|
||||
const style = node.style;
|
||||
|
||||
expect(style.verticalAlign).toEqual('-0.125em');
|
||||
expect(style.verticalAlign).toEqual('');
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,7 @@ import { render } from '@testing-library/svelte';
|
||||
import { Icon } from '../../dist/iconify';
|
||||
|
||||
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: 32,
|
||||
};
|
||||
@ -86,11 +85,11 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const component = render(Icon, {
|
||||
icon: iconData,
|
||||
flip: 'horizontal',
|
||||
hFlip: false,
|
||||
flip: 'horizontal',
|
||||
});
|
||||
const node = component.container.querySelector('svg');
|
||||
|
||||
@ -103,7 +102,6 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean as string', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
const component = render(Icon, {
|
||||
icon: iconData,
|
||||
flip: 'vertical',
|
||||
@ -118,7 +116,6 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('wrong case', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
const component = render(Icon, {
|
||||
icon: iconData,
|
||||
vflip: true,
|
||||
|
@ -2,8 +2,7 @@ import { render } from '@testing-library/svelte';
|
||||
import { Icon } from '../../dist/offline';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -34,11 +33,11 @@ describe('Inline attribute', () => {
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const component = render(Icon, { icon: iconData, inline: 'false' });
|
||||
const node = component.container.querySelector('svg');
|
||||
const style = node.style;
|
||||
|
||||
expect(style.verticalAlign).toEqual('-0.125em');
|
||||
expect(style.verticalAlign).toEqual('');
|
||||
});
|
||||
});
|
||||
|
@ -2,8 +2,7 @@ import { render } from '@testing-library/svelte';
|
||||
import { Icon } from '../../dist/offline';
|
||||
|
||||
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: 32,
|
||||
};
|
||||
@ -86,11 +85,11 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const component = render(Icon, {
|
||||
icon: iconData,
|
||||
flip: 'horizontal',
|
||||
hFlip: false,
|
||||
flip: 'horizontal',
|
||||
});
|
||||
const node = component.container.querySelector('svg');
|
||||
|
||||
@ -103,7 +102,6 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean as string', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
const component = render(Icon, {
|
||||
icon: iconData,
|
||||
flip: 'vertical',
|
||||
@ -118,7 +116,6 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('wrong case', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
const component = render(Icon, {
|
||||
icon: iconData,
|
||||
vflip: true,
|
||||
|
18
packages/vue/package-lock.json
generated
18
packages/vue/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@iconify/vue",
|
||||
"version": "3.0.0-dev",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@iconify/vue",
|
||||
"version": "3.0.0-dev",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.12.0",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
@ -547,9 +547,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
@ -24398,9 +24398,9 @@
|
||||
}
|
||||
},
|
||||
"@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/vue",
|
||||
"description": "Iconify icon component for Vue 3.",
|
||||
"author": "Vjacheslav Trushkin",
|
||||
"version": "3.0.0-alpha.0",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"license": "MIT",
|
||||
"bugs": "https://github.com/iconify/iconify/issues",
|
||||
"homepage": "https://iconify.design/",
|
||||
@ -24,7 +24,7 @@
|
||||
"module": "dist/iconify.mjs",
|
||||
"types": "dist/iconify.d.ts",
|
||||
"devDependencies": {
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.12.0",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
|
@ -27,6 +27,7 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import type { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/core/lib/icon';
|
||||
|
||||
// Modules
|
||||
@ -74,6 +75,8 @@ import {
|
||||
|
||||
// Properties
|
||||
import {
|
||||
RawIconCustomisations,
|
||||
IconifyIconOnLoad,
|
||||
IconProps,
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconProps,
|
||||
@ -97,7 +100,7 @@ export {
|
||||
// JSON stuff
|
||||
export { IconifyIcon, IconifyJSON, IconifyIconName };
|
||||
|
||||
// Customisations
|
||||
// Customisations and icon props
|
||||
export {
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconSize,
|
||||
@ -105,6 +108,7 @@ export {
|
||||
IconifyVerticalIconAlignment,
|
||||
IconifyIconProps,
|
||||
IconProps,
|
||||
IconifyIconOnLoad,
|
||||
};
|
||||
|
||||
// API
|
||||
@ -120,6 +124,9 @@ export {
|
||||
PartialIconifyAPIConfig,
|
||||
};
|
||||
|
||||
// Builder functions
|
||||
export { RawIconCustomisations, IconifyIconBuildResult };
|
||||
|
||||
/* Browser cache */
|
||||
export { IconifyBrowserCacheType };
|
||||
|
||||
@ -169,6 +176,11 @@ export const calculateSize = builderFunctions.calculateSize;
|
||||
*/
|
||||
export const replaceIDs = builderFunctions.replaceIDs;
|
||||
|
||||
/**
|
||||
* Build SVG
|
||||
*/
|
||||
export const buildIcon = builderFunctions.buildIcon;
|
||||
|
||||
/* API functions */
|
||||
/**
|
||||
* Load icons
|
||||
@ -338,7 +350,7 @@ export const Icon = defineComponent({
|
||||
}
|
||||
},
|
||||
// Get data for icon to render or null
|
||||
getIcon(icon) {
|
||||
getIcon(icon: IconifyIcon | string, onload?: IconifyIconOnLoad) {
|
||||
// Icon is an object
|
||||
if (
|
||||
typeof icon === 'object' &&
|
||||
@ -376,8 +388,13 @@ export const Icon = defineComponent({
|
||||
}
|
||||
|
||||
// Icon data is available
|
||||
this._name = icon;
|
||||
this.abortLoading();
|
||||
if (this._name !== icon) {
|
||||
this._name = icon;
|
||||
if (onload) {
|
||||
onload(icon);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
},
|
||||
@ -393,7 +410,7 @@ export const Icon = defineComponent({
|
||||
|
||||
// Get icon data
|
||||
const props = this.$attrs;
|
||||
const icon = this.getIcon(props.icon);
|
||||
const icon = this.getIcon(props.icon, props.onLoad);
|
||||
|
||||
// Validate icon object
|
||||
if (!icon) {
|
||||
|
@ -1,14 +1,21 @@
|
||||
import { IconifyIcon } from '@iconify/types';
|
||||
import { IconifyIconCustomisations as IconCustomisations } from '@iconify/core/lib/customisations';
|
||||
import { IconifyIconCustomisations as RawIconCustomisations } from '@iconify/core/lib/customisations';
|
||||
|
||||
export { RawIconCustomisations };
|
||||
|
||||
// Allow rotation to be string
|
||||
/**
|
||||
* Icon customisations
|
||||
*/
|
||||
export type IconifyIconCustomisations = IconCustomisations & {
|
||||
export type IconifyIconCustomisations = RawIconCustomisations & {
|
||||
rotate?: string | number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for when icon has been loaded (only triggered for icons loaded from API)
|
||||
*/
|
||||
export type IconifyIconOnLoad = (name: string) => void;
|
||||
|
||||
/**
|
||||
* Icon properties
|
||||
*/
|
||||
@ -33,6 +40,9 @@ interface IconifyElementProps {
|
||||
|
||||
// Style
|
||||
style?: unknown;
|
||||
|
||||
// Callback to call when icon data has been loaded. Used only for icons loaded from API
|
||||
onLoad?: IconifyIconOnLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@ import { IconifyIcon } from '@iconify/types';
|
||||
import {
|
||||
FullIconCustomisations,
|
||||
defaults,
|
||||
mergeCustomisations,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
import {
|
||||
flipFromString,
|
||||
@ -32,14 +33,19 @@ let customisationAliases = {};
|
||||
['horizontal', 'vertical'].forEach(prefix => {
|
||||
['Align', 'Flip'].forEach(suffix => {
|
||||
const attr = prefix.slice(0, 1) + suffix;
|
||||
const value = {
|
||||
attr,
|
||||
boolean: suffix === 'Flip',
|
||||
};
|
||||
|
||||
// vertical-align
|
||||
customisationAliases[prefix + '-' + suffix.toLowerCase()] = attr;
|
||||
customisationAliases[prefix + '-' + suffix.toLowerCase()] = value;
|
||||
// v-align
|
||||
customisationAliases[
|
||||
prefix.slice(0, 1) + '-' + suffix.toLowerCase()
|
||||
] = attr;
|
||||
] = value;
|
||||
// verticalAlign
|
||||
customisationAliases[prefix + suffix] = attr;
|
||||
customisationAliases[prefix + suffix] = value;
|
||||
});
|
||||
});
|
||||
|
||||
@ -60,7 +66,7 @@ export const render = (
|
||||
props: IconProps
|
||||
): VNode => {
|
||||
// Split properties
|
||||
const customisations = merge(
|
||||
const customisations = mergeCustomisations(
|
||||
defaults,
|
||||
props as IconifyIconCustomisations
|
||||
) as FullIconCustomisations;
|
||||
@ -75,10 +81,22 @@ export const render = (
|
||||
// Get element properties
|
||||
for (let key in props) {
|
||||
const value = props[key];
|
||||
if (value === void 0) {
|
||||
continue;
|
||||
}
|
||||
switch (key) {
|
||||
// Properties to ignore
|
||||
case 'icon':
|
||||
case 'style':
|
||||
case 'onLoad':
|
||||
break;
|
||||
|
||||
// Boolean attributes
|
||||
case 'inline':
|
||||
case 'hFlip':
|
||||
case 'vFlip':
|
||||
customisations[key] =
|
||||
value === true || value === 'true' || value === 1;
|
||||
break;
|
||||
|
||||
// Flip as string: 'horizontal,vertical'
|
||||
@ -121,7 +139,20 @@ export const render = (
|
||||
default:
|
||||
if (customisationAliases[key] !== void 0) {
|
||||
// Aliases for customisations
|
||||
customisations[customisationAliases[key]] = value;
|
||||
if (
|
||||
customisationAliases[key].boolean &&
|
||||
(value === true || value === 'true' || value === 1)
|
||||
) {
|
||||
// Check for boolean
|
||||
customisations[customisationAliases[key].attr] = true;
|
||||
} else if (
|
||||
!customisationAliases[key].boolean &&
|
||||
typeof value === 'string' &&
|
||||
value !== ''
|
||||
) {
|
||||
// String
|
||||
customisations[customisationAliases[key].attr] = value;
|
||||
}
|
||||
} else if (defaults[key] === void 0) {
|
||||
// Copy missing property if it does not exist in customisations
|
||||
componentProps[key] = value;
|
||||
|
@ -15,6 +15,8 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
prefix,
|
||||
@ -46,7 +48,14 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
onLoadCalled = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
const html = wrapper.html().replace(/\s*\n\s*/g, '');
|
||||
@ -56,6 +65,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// Make sure onLoad has been called
|
||||
expect(onLoadCalled).toEqual(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -64,6 +76,8 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'mock-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
prefix,
|
||||
@ -77,6 +91,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -92,6 +109,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
expect(onLoadCalled).toEqual(true);
|
||||
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
@ -104,12 +124,22 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
onLoadCalled = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
|
||||
// Should render empty icon
|
||||
expect(wrapper.html()).toEqual('<!---->');
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
});
|
||||
|
||||
test('missing icon', done => {
|
||||
@ -148,7 +178,12 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
methods: {
|
||||
onLoad() {
|
||||
throw new Error('onLoad called for empty icon!');
|
||||
},
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
|
||||
|
@ -24,6 +24,26 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
|
||||
const onLoad = name => {
|
||||
// onLoad should be called only once per icon
|
||||
switch (name) {
|
||||
// First onLoad call
|
||||
case iconName:
|
||||
expect(onLoadCalled).toEqual('');
|
||||
break;
|
||||
|
||||
// Second onLoad call
|
||||
case iconName2:
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unexpected onLoad('${name}') call`);
|
||||
}
|
||||
onLoadCalled = name;
|
||||
};
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
@ -38,6 +58,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual('');
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -52,6 +75,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
|
||||
wrapper.setProps({
|
||||
icon: iconName2,
|
||||
});
|
||||
@ -73,6 +99,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName2)).toEqual(false);
|
||||
|
||||
// onLoad should have been called only once for previous icon
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -87,6 +116,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// onLoad should have been called for second icon
|
||||
expect(onLoadCalled).toEqual(iconName2);
|
||||
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
@ -99,12 +131,18 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
|
||||
methods: {
|
||||
onLoad,
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
|
||||
// Should render placeholder
|
||||
expect(wrapper.html()).toEqual('<!---->');
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual('');
|
||||
});
|
||||
|
||||
test('changing icon property while loading', done => {
|
||||
|
@ -30,6 +30,10 @@ describe('Creating component', () => {
|
||||
const wrapper = mount(Icon, {
|
||||
props: {
|
||||
icon: iconData,
|
||||
onLoad: () => {
|
||||
// Should be called only for icons loaded from API
|
||||
throw new Error('onLoad called for object!');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -25,7 +25,7 @@ describe('Inline attribute', () => {
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" inline="false" />`,
|
||||
@ -37,7 +37,9 @@ describe('Inline attribute', () => {
|
||||
};
|
||||
|
||||
const wrapper = mount(Wrapper, {});
|
||||
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||
expect(wrapper.html()).not.toContain(
|
||||
'style="vertical-align: -0.125em;"'
|
||||
);
|
||||
});
|
||||
|
||||
test('true', () => {
|
||||
|
@ -110,10 +110,10 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" flip="horizontal" :hFlip="false" />`,
|
||||
template: `<Icon :icon="icon" :hFlip="false" flip="horizontal" />`,
|
||||
data() {
|
||||
return {
|
||||
icon: iconData,
|
||||
|
@ -25,7 +25,7 @@ describe('Inline attribute', () => {
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" inline="false" />`,
|
||||
@ -37,7 +37,9 @@ describe('Inline attribute', () => {
|
||||
};
|
||||
|
||||
const wrapper = mount(Wrapper, {});
|
||||
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||
expect(wrapper.html()).not.toContain(
|
||||
'style="vertical-align: -0.125em;"'
|
||||
);
|
||||
});
|
||||
|
||||
test('true', () => {
|
||||
|
@ -110,10 +110,10 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" flip="horizontal" :hFlip="false" />`,
|
||||
template: `<Icon :icon="icon" :hFlip="false" flip="horizontal" />`,
|
||||
data() {
|
||||
return {
|
||||
icon: iconData,
|
||||
|
18
packages/vue2/package-lock.json
generated
18
packages/vue2/package-lock.json
generated
@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@iconify/vue2",
|
||||
"version": "1.0.0-alpha.0",
|
||||
"version": "1.0.0-alpha.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@iconify/vue2",
|
||||
"version": "1.0.0-alpha.0",
|
||||
"version": "1.0.0-alpha.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.15.1",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
@ -707,9 +707,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
@ -10091,9 +10091,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@iconify/core": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.0.tgz",
|
||||
"integrity": "sha512-jzGZQMOqoPpKFZ4K4dQ6gNcDqALoJE02FMExm+kcN4vp2GJ5JKCccYxJLBWTmR23vVeZzpxlCtL3KSKjUfe2Kw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-gbPClcrRJ7sIKgwcEPLUaT1u8PzpOGdsCM3O63wJa5FYosC3ZZBymqR1LFT6MSiPWGlF2XowabzoHS8HaICEpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cyberalien/redundancy": "^1.1.0",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/vue2",
|
||||
"description": "Iconify icon component for Vue 2.",
|
||||
"author": "Vjacheslav Trushkin",
|
||||
"version": "1.0.0-alpha.0",
|
||||
"version": "1.0.0-alpha.1",
|
||||
"license": "MIT",
|
||||
"bugs": "https://github.com/iconify/iconify/issues",
|
||||
"homepage": "https://iconify.design/",
|
||||
@ -24,7 +24,7 @@
|
||||
"module": "dist/iconify.mjs",
|
||||
"types": "dist/iconify.d.ts",
|
||||
"devDependencies": {
|
||||
"@iconify/core": "^1.0.0",
|
||||
"@iconify/core": "^1.0.1",
|
||||
"@iconify/types": "^1.0.6",
|
||||
"@microsoft/api-extractor": "^7.15.1",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import type { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/core/lib/icon';
|
||||
|
||||
// Modules
|
||||
@ -66,6 +67,8 @@ import {
|
||||
|
||||
// Properties
|
||||
import {
|
||||
RawIconCustomisations,
|
||||
IconifyIconOnLoad,
|
||||
IconProps,
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconProps,
|
||||
@ -89,7 +92,7 @@ export {
|
||||
// JSON stuff
|
||||
export { IconifyIcon, IconifyJSON, IconifyIconName };
|
||||
|
||||
// Customisations
|
||||
// Customisations and icon props
|
||||
export {
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconSize,
|
||||
@ -97,6 +100,7 @@ export {
|
||||
IconifyVerticalIconAlignment,
|
||||
IconifyIconProps,
|
||||
IconProps,
|
||||
IconifyIconOnLoad,
|
||||
};
|
||||
|
||||
// API
|
||||
@ -112,6 +116,9 @@ export {
|
||||
PartialIconifyAPIConfig,
|
||||
};
|
||||
|
||||
// Builder functions
|
||||
export { RawIconCustomisations, IconifyIconBuildResult };
|
||||
|
||||
/* Browser cache */
|
||||
export { IconifyBrowserCacheType };
|
||||
|
||||
@ -161,6 +168,11 @@ export const calculateSize = builderFunctions.calculateSize;
|
||||
*/
|
||||
export const replaceIDs = builderFunctions.replaceIDs;
|
||||
|
||||
/**
|
||||
* Build SVG
|
||||
*/
|
||||
export const buildIcon = builderFunctions.buildIcon;
|
||||
|
||||
/* API functions */
|
||||
/**
|
||||
* Load icons
|
||||
@ -227,10 +239,10 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
IconifyPreload: IconifyJSON[] | IconifyJSON;
|
||||
}
|
||||
if (
|
||||
((_window as unknown) as WindowWithIconifyPreload).IconifyPreload !==
|
||||
(_window as unknown as WindowWithIconifyPreload).IconifyPreload !==
|
||||
void 0
|
||||
) {
|
||||
const preload = ((_window as unknown) as WindowWithIconifyPreload)
|
||||
const preload = (_window as unknown as WindowWithIconifyPreload)
|
||||
.IconifyPreload;
|
||||
const err = 'Invalid IconifyPreload syntax.';
|
||||
if (typeof preload === 'object' && preload !== null) {
|
||||
@ -261,10 +273,10 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
IconifyProviders: Record<string, PartialIconifyAPIConfig>;
|
||||
}
|
||||
if (
|
||||
((_window as unknown) as WindowWithIconifyProviders)
|
||||
.IconifyProviders !== void 0
|
||||
(_window as unknown as WindowWithIconifyProviders).IconifyProviders !==
|
||||
void 0
|
||||
) {
|
||||
const providers = ((_window as unknown) as WindowWithIconifyProviders)
|
||||
const providers = (_window as unknown as WindowWithIconifyProviders)
|
||||
.IconifyProviders;
|
||||
if (typeof providers === 'object' && providers !== null) {
|
||||
for (let key in providers) {
|
||||
@ -328,7 +340,7 @@ export const Icon = Vue.extend({
|
||||
}
|
||||
},
|
||||
// Get data for icon to render or null
|
||||
getIcon(icon) {
|
||||
getIcon(icon: IconifyIcon | string, onload?: IconifyIconOnLoad) {
|
||||
// Icon is an object
|
||||
if (
|
||||
typeof icon === 'object' &&
|
||||
@ -366,8 +378,13 @@ export const Icon = Vue.extend({
|
||||
}
|
||||
|
||||
// Icon data is available
|
||||
this._name = icon;
|
||||
this.abortLoading();
|
||||
if (this._name !== icon) {
|
||||
this._name = icon;
|
||||
if (onload) {
|
||||
onload(icon);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
},
|
||||
@ -385,7 +402,7 @@ export const Icon = Vue.extend({
|
||||
: createElement('span', result);
|
||||
}
|
||||
}
|
||||
return (null as unknown) as VNode;
|
||||
return null as unknown as VNode;
|
||||
}
|
||||
if (!this.mounted) {
|
||||
return placeholder(this.$slots);
|
||||
@ -393,7 +410,7 @@ export const Icon = Vue.extend({
|
||||
|
||||
// Get icon data
|
||||
const props = this.$attrs;
|
||||
const icon = this.getIcon(props.icon);
|
||||
const icon = this.getIcon(props.icon, props.onLoad);
|
||||
|
||||
// Validate icon object
|
||||
if (!icon) {
|
||||
|
@ -1,14 +1,21 @@
|
||||
import { IconifyIcon } from '@iconify/types';
|
||||
import { IconifyIconCustomisations as IconCustomisations } from '@iconify/core/lib/customisations';
|
||||
import { IconifyIconCustomisations as RawIconCustomisations } from '@iconify/core/lib/customisations';
|
||||
|
||||
export { RawIconCustomisations };
|
||||
|
||||
// Allow rotation to be string
|
||||
/**
|
||||
* Icon customisations
|
||||
*/
|
||||
export type IconifyIconCustomisations = IconCustomisations & {
|
||||
export type IconifyIconCustomisations = RawIconCustomisations & {
|
||||
rotate?: string | number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for when icon has been loaded (only triggered for icons loaded from API)
|
||||
*/
|
||||
export type IconifyIconOnLoad = (name: string) => void;
|
||||
|
||||
/**
|
||||
* Icon properties
|
||||
*/
|
||||
@ -33,6 +40,9 @@ interface IconifyElementProps {
|
||||
|
||||
// Style
|
||||
style?: unknown;
|
||||
|
||||
// Callback to call when icon data has been loaded. Used only for icons loaded from API
|
||||
onLoad?: IconifyIconOnLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@ import { IconifyIcon } from '@iconify/types';
|
||||
import {
|
||||
FullIconCustomisations,
|
||||
defaults,
|
||||
mergeCustomisations,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
import {
|
||||
flipFromString,
|
||||
@ -32,22 +33,21 @@ let customisationAliases = {};
|
||||
['horizontal', 'vertical'].forEach((prefix) => {
|
||||
['Align', 'Flip'].forEach((suffix) => {
|
||||
const attr = prefix.slice(0, 1) + suffix;
|
||||
const value = {
|
||||
attr,
|
||||
boolean: suffix === 'Flip',
|
||||
};
|
||||
|
||||
// vertical-align
|
||||
customisationAliases[prefix + '-' + suffix.toLowerCase()] = attr;
|
||||
customisationAliases[prefix + '-' + suffix.toLowerCase()] = value;
|
||||
// v-align
|
||||
customisationAliases[
|
||||
prefix.slice(0, 1) + '-' + suffix.toLowerCase()
|
||||
] = attr;
|
||||
customisationAliases[prefix.slice(0, 1) + '-' + suffix.toLowerCase()] =
|
||||
value;
|
||||
// verticalAlign
|
||||
customisationAliases[prefix + suffix] = attr;
|
||||
customisationAliases[prefix + suffix] = value;
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Interface for inline style
|
||||
*/
|
||||
type VNodeStyle = (string | Record<string, unknown>)[];
|
||||
|
||||
/**
|
||||
* Render icon
|
||||
*/
|
||||
@ -64,7 +64,7 @@ export const render = (
|
||||
icon: Required<IconifyIcon>
|
||||
): VNode => {
|
||||
// Split properties
|
||||
const customisations = merge(
|
||||
const customisations = mergeCustomisations(
|
||||
defaults,
|
||||
props as IconifyIconCustomisations
|
||||
) as FullIconCustomisations;
|
||||
@ -76,10 +76,22 @@ export const render = (
|
||||
// Get element properties
|
||||
for (let key in props) {
|
||||
const value = props[key];
|
||||
if (value === void 0) {
|
||||
continue;
|
||||
}
|
||||
switch (key) {
|
||||
// Properties to ignore
|
||||
case 'icon':
|
||||
case 'style':
|
||||
case 'onLoad':
|
||||
break;
|
||||
|
||||
// Boolean attributes
|
||||
case 'inline':
|
||||
case 'hFlip':
|
||||
case 'vFlip':
|
||||
customisations[key] =
|
||||
value === true || value === 'true' || value === 1;
|
||||
break;
|
||||
|
||||
// Flip as string: 'horizontal,vertical'
|
||||
@ -122,7 +134,20 @@ export const render = (
|
||||
default:
|
||||
if (customisationAliases[key] !== void 0) {
|
||||
// Aliases for customisations
|
||||
customisations[customisationAliases[key]] = value;
|
||||
if (
|
||||
customisationAliases[key].boolean &&
|
||||
(value === true || value === 'true' || value === 1)
|
||||
) {
|
||||
// Check for boolean
|
||||
customisations[customisationAliases[key].attr] = true;
|
||||
} else if (
|
||||
!customisationAliases[key].boolean &&
|
||||
typeof value === 'string' &&
|
||||
value !== ''
|
||||
) {
|
||||
// String
|
||||
customisations[customisationAliases[key].attr] = value;
|
||||
}
|
||||
} else if (defaults[key] === void 0) {
|
||||
// Copy missing property if it does not exist in customisations
|
||||
componentProps[key] = value;
|
||||
|
@ -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,8 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'render-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
prefix,
|
||||
@ -46,7 +47,14 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
onLoadCalled = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
const html = wrapper.html().replace(/\s*\n\s*/g, '');
|
||||
@ -56,6 +64,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// Make sure onLoad has been called
|
||||
expect(onLoadCalled).toEqual(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -64,6 +75,8 @@ describe('Rendering icon', () => {
|
||||
const prefix = nextPrefix();
|
||||
const name = 'mock-test';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
let onLoadCalled = false;
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
prefix,
|
||||
@ -77,6 +90,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -92,6 +108,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
expect(onLoadCalled).toEqual(true);
|
||||
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
@ -104,12 +123,22 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
methods: {
|
||||
onLoad(name) {
|
||||
expect(name).toEqual(iconName);
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
onLoadCalled = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
|
||||
// Should render empty icon
|
||||
expect(wrapper.html()).toEqual('');
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual(false);
|
||||
});
|
||||
|
||||
test('missing icon', (done) => {
|
||||
@ -148,7 +177,12 @@ describe('Rendering icon', () => {
|
||||
// Render component
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon icon="${iconName}" />`,
|
||||
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
|
||||
methods: {
|
||||
onLoad() {
|
||||
throw new Error('onLoad called for empty icon!');
|
||||
},
|
||||
},
|
||||
};
|
||||
const wrapper = mount(Wrapper, {});
|
||||
|
||||
|
@ -4,15 +4,13 @@ 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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
@ -24,6 +22,26 @@ describe('Rendering icon', () => {
|
||||
const name2 = 'changing-prop2';
|
||||
const iconName = `@${provider}:${prefix}:${name}`;
|
||||
const iconName2 = `@${provider}:${prefix}:${name2}`;
|
||||
let onLoadCalled = ''; // Name of icon from last onLoad call
|
||||
|
||||
const onLoad = (name) => {
|
||||
// onLoad should be called only once per icon
|
||||
switch (name) {
|
||||
// First onLoad call
|
||||
case iconName:
|
||||
expect(onLoadCalled).toEqual('');
|
||||
break;
|
||||
|
||||
// Second onLoad call
|
||||
case iconName2:
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unexpected onLoad('${name}') call`);
|
||||
}
|
||||
onLoadCalled = name;
|
||||
};
|
||||
|
||||
mockAPIData({
|
||||
provider,
|
||||
@ -38,6 +56,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName)).toEqual(false);
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual('');
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -52,6 +73,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// onLoad should have been called
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
|
||||
wrapper.setProps({
|
||||
icon: iconName2,
|
||||
});
|
||||
@ -73,6 +97,9 @@ describe('Rendering icon', () => {
|
||||
// Icon should not have loaded yet
|
||||
expect(iconExists(iconName2)).toEqual(false);
|
||||
|
||||
// onLoad should have been called only once for previous icon
|
||||
expect(onLoadCalled).toEqual(iconName);
|
||||
|
||||
// Send icon data
|
||||
next();
|
||||
|
||||
@ -87,6 +114,9 @@ describe('Rendering icon', () => {
|
||||
'<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>'
|
||||
);
|
||||
|
||||
// onLoad should have been called for second icon
|
||||
expect(onLoadCalled).toEqual(iconName2);
|
||||
|
||||
done();
|
||||
}, 0);
|
||||
}, 0);
|
||||
@ -100,11 +130,15 @@ describe('Rendering icon', () => {
|
||||
const wrapper = mount(Icon, {
|
||||
propsData: {
|
||||
icon: iconName,
|
||||
onLoad,
|
||||
},
|
||||
});
|
||||
|
||||
// Should render placeholder
|
||||
expect(wrapper.html()).toEqual('');
|
||||
|
||||
// onLoad should not have been called yet
|
||||
expect(onLoadCalled).toEqual('');
|
||||
});
|
||||
|
||||
test('changing icon property while loading', (done) => {
|
||||
|
@ -2,8 +2,7 @@ import { mount } from '@vue/test-utils';
|
||||
import { Icon } from '../../dist/iconify';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -30,6 +29,10 @@ describe('Creating component', () => {
|
||||
const wrapper = mount(Icon, {
|
||||
propsData: {
|
||||
icon: iconData,
|
||||
onLoad: () => {
|
||||
// Should be called only for icons loaded from API
|
||||
throw new Error('onLoad called for object!');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -2,8 +2,7 @@ import { mount } from '@vue/test-utils';
|
||||
import { Icon } from '../../dist/iconify';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -25,7 +24,7 @@ describe('Inline attribute', () => {
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" inline="false" />`,
|
||||
@ -37,7 +36,9 @@ describe('Inline attribute', () => {
|
||||
};
|
||||
|
||||
const wrapper = mount(Wrapper, {});
|
||||
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||
expect(wrapper.html()).not.toContain(
|
||||
'style="vertical-align: -0.125em;"'
|
||||
);
|
||||
});
|
||||
|
||||
test('true', () => {
|
||||
|
@ -2,8 +2,7 @@ import { mount } from '@vue/test-utils';
|
||||
import { Icon } from '../../dist/iconify';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -110,10 +109,10 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" flip="horizontal" :hFlip="false" />`,
|
||||
template: `<Icon :icon="icon" :hFlip="false" flip="horizontal" />`,
|
||||
data() {
|
||||
return {
|
||||
icon: iconData,
|
||||
|
@ -2,8 +2,7 @@ import { mount } from '@vue/test-utils';
|
||||
import { Icon } from '../../dist/offline';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -25,7 +24,7 @@ describe('Inline attribute', () => {
|
||||
});
|
||||
|
||||
test('false string', () => {
|
||||
// "false" = true
|
||||
// "false" should be ignored
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" inline="false" />`,
|
||||
@ -37,7 +36,9 @@ describe('Inline attribute', () => {
|
||||
};
|
||||
|
||||
const wrapper = mount(Wrapper, {});
|
||||
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||
expect(wrapper.html()).not.toContain(
|
||||
'style="vertical-align: -0.125em;"'
|
||||
);
|
||||
});
|
||||
|
||||
test('true', () => {
|
||||
|
@ -2,8 +2,7 @@ import { mount } from '@vue/test-utils';
|
||||
import { Icon } from '../../dist/offline';
|
||||
|
||||
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,
|
||||
};
|
||||
@ -110,10 +109,10 @@ describe('Flip', () => {
|
||||
});
|
||||
|
||||
test('shorthand and boolean', () => {
|
||||
// 'flip' is processed after 'hFlip', overwriting value
|
||||
// 'flip' is processed after 'hFlip' because of order of elements in object, overwriting value
|
||||
const Wrapper = {
|
||||
components: { Icon },
|
||||
template: `<Icon :icon="icon" flip="horizontal" :hFlip="false" />`,
|
||||
template: `<Icon :icon="icon" :hFlip="false" flip="horizontal" />`,
|
||||
data() {
|
||||
return {
|
||||
icon: iconData,
|
||||
|
Loading…
Reference in New Issue
Block a user