mirror of
https://github.com/iconify/iconify.git
synced 2024-11-14 00:34:04 +00:00
Change Vue 2 component from functional to class in preparation for API support
This commit is contained in:
parent
a4422ec145
commit
56df8fa1e8
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||||
"mainEntryPointFilePath": "lib/IconifyIcon.d.ts",
|
"mainEntryPointFilePath": "lib/iconify.d.ts",
|
||||||
"bundledPackages": [
|
"bundledPackages": [
|
||||||
"@iconify/types",
|
"@iconify/types",
|
||||||
"@iconify/core",
|
"@iconify/core",
|
||||||
@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"dtsRollup": {
|
"dtsRollup": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"untrimmedFilePath": "<projectFolder>/dist/IconifyIcon.d.ts"
|
"untrimmedFilePath": "<projectFolder>/dist/iconify.d.ts"
|
||||||
},
|
},
|
||||||
"tsdocMetadata": {
|
"tsdocMetadata": {
|
||||||
"enabled": false
|
"enabled": false
|
43
packages/vue2/api-extractor.offline.json
Normal file
43
packages/vue2/api-extractor.offline.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||||
|
"mainEntryPointFilePath": "lib/offline.d.ts",
|
||||||
|
"bundledPackages": [
|
||||||
|
"@iconify/types",
|
||||||
|
"@iconify/core",
|
||||||
|
"@cyberalien/redundancy"
|
||||||
|
],
|
||||||
|
"compiler": {},
|
||||||
|
"apiReport": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"docModel": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"dtsRollup": {
|
||||||
|
"enabled": true,
|
||||||
|
"untrimmedFilePath": "<projectFolder>/dist/offline.d.ts"
|
||||||
|
},
|
||||||
|
"tsdocMetadata": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"compilerMessageReporting": {
|
||||||
|
"default": {
|
||||||
|
"logLevel": "warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extractorMessageReporting": {
|
||||||
|
"default": {
|
||||||
|
"logLevel": "warning"
|
||||||
|
},
|
||||||
|
"ae-missing-release-tag": {
|
||||||
|
"logLevel": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tsdocMessageReporting": {
|
||||||
|
"default": {
|
||||||
|
"logLevel": "warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,21 +2,18 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
|
|
||||||
// const packagesDir = path.dirname(path.dirname(__dirname)) + '/packages';
|
const packagesDir = path.dirname(__dirname);
|
||||||
|
|
||||||
// List of commands to run
|
// List of commands to run
|
||||||
const commands = [];
|
const commands = [];
|
||||||
|
|
||||||
// Parse command line
|
// Parse command line
|
||||||
const compile = {
|
const compile = {
|
||||||
// core: false,
|
core: false,
|
||||||
lib: true,
|
lib: true,
|
||||||
dist: true,
|
dist: true,
|
||||||
api: true,
|
api: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Disable compiling dependencies because project was moved to archive
|
|
||||||
/*
|
|
||||||
process.argv.slice(2).forEach((cmd) => {
|
process.argv.slice(2).forEach((cmd) => {
|
||||||
if (cmd.slice(0, 2) !== '--') {
|
if (cmd.slice(0, 2) !== '--') {
|
||||||
return;
|
return;
|
||||||
@ -79,7 +76,6 @@ if (compile.core) {
|
|||||||
cwd: packagesDir + '/core',
|
cwd: packagesDir + '/core',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Compile other packages
|
// Compile other packages
|
||||||
Object.keys(compile).forEach((key) => {
|
Object.keys(compile).forEach((key) => {
|
||||||
|
@ -6,4 +6,5 @@ module.exports = {
|
|||||||
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
|
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
|
||||||
},
|
},
|
||||||
collectCoverage: false,
|
collectCoverage: false,
|
||||||
|
testMatch: ['**/tests/**/*.test.js'],
|
||||||
};
|
};
|
||||||
|
@ -15,13 +15,14 @@
|
|||||||
"build": "node build",
|
"build": "node build",
|
||||||
"build:lib": "tsc -b",
|
"build:lib": "tsc -b",
|
||||||
"build:dist": "rollup -c rollup.config.js",
|
"build:dist": "rollup -c rollup.config.js",
|
||||||
"build:api": "api-extractor run --local --verbose",
|
"prebuild:api": "api-extractor run --local --verbose --config api-extractor.offline.json",
|
||||||
|
"build:api": "api-extractor run --local --verbose --config api-extractor.iconify.json",
|
||||||
"pretest": "npm run build",
|
"pretest": "npm run build",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"main": "dist/IconifyIcon.umd.js",
|
"main": "dist/iconify.js",
|
||||||
"module": "dist/IconifyIcon.esm.js",
|
"module": "dist/iconify.mjs",
|
||||||
"types": "dist/IconifyIcon.d.ts",
|
"types": "dist/iconify.d.ts",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify/core": "^1.0.0-rc.3",
|
"@iconify/core": "^1.0.0-rc.3",
|
||||||
"@microsoft/api-extractor": "^7.15.1",
|
"@microsoft/api-extractor": "^7.15.1",
|
||||||
|
@ -1,78 +1,45 @@
|
|||||||
import resolve from '@rollup/plugin-node-resolve';
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
import commonjs from '@rollup/plugin-commonjs';
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
import buble from '@rollup/plugin-buble';
|
import buble from '@rollup/plugin-buble';
|
||||||
// import { terser } from 'rollup-plugin-terser';
|
|
||||||
|
|
||||||
const name = 'IconifyIcon';
|
const names = ['offline', 'iconify'];
|
||||||
|
const component = 'Icon';
|
||||||
|
|
||||||
// Module footer
|
const config = [];
|
||||||
const footer = `
|
|
||||||
// Export as ES module
|
|
||||||
if (typeof exports === 'object') {
|
|
||||||
try {
|
|
||||||
exports.__esModule = true;
|
|
||||||
exports.default = ${name};
|
|
||||||
} catch (err) {
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
// Export configuration
|
// Write all packages
|
||||||
const config = [
|
names.forEach((name) => {
|
||||||
// ES Module
|
// ES module
|
||||||
{
|
config.push({
|
||||||
input: `lib/${name}.js`,
|
input: `lib/${name}.js`,
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
file: `dist/${name}.esm.js`,
|
file: `dist/${name}.mjs`,
|
||||||
format: 'esm',
|
format: 'esm',
|
||||||
exports: 'named',
|
exports: 'named',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
external: ['vue'],
|
||||||
plugins: [resolve(), commonjs(), buble()],
|
plugins: [resolve(), commonjs(), buble()],
|
||||||
},
|
});
|
||||||
// UMD Module
|
|
||||||
{
|
|
||||||
input: `lib/${name}.js`,
|
|
||||||
output: [
|
|
||||||
{
|
|
||||||
file: `dist/${name}.umd.js`,
|
|
||||||
format: 'umd',
|
|
||||||
name,
|
|
||||||
exports: 'named',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
plugins: [resolve(), commonjs(), buble()],
|
|
||||||
},
|
|
||||||
/*
|
|
||||||
// Web and module
|
|
||||||
// "unpkg": "dist/IconifyIcon.min.js",
|
|
||||||
|
|
||||||
{
|
// UMD module
|
||||||
|
config.push({
|
||||||
input: `lib/${name}.js`,
|
input: `lib/${name}.js`,
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
file: `dist/${name}.js`,
|
file: `dist/${name}.js`,
|
||||||
name,
|
format: 'umd',
|
||||||
format: 'iife',
|
name: component,
|
||||||
footer,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
plugins: [resolve(), commonjs(), buble()],
|
|
||||||
},
|
|
||||||
// Web
|
|
||||||
{
|
|
||||||
input: `lib/${name}.js`,
|
|
||||||
output: [
|
|
||||||
{
|
|
||||||
file: `dist/${name}.min.js`,
|
|
||||||
name,
|
|
||||||
exports: 'named',
|
exports: 'named',
|
||||||
format: 'iife',
|
globals: {
|
||||||
|
vue: 'Vue',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
plugins: [resolve(), commonjs(), buble(), terser()],
|
external: ['vue'],
|
||||||
},
|
plugins: [resolve(), commonjs(), buble()],
|
||||||
*/
|
});
|
||||||
];
|
});
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
@ -1,339 +0,0 @@
|
|||||||
import _Vue, { PluginFunction, VueConstructor, VNode, VNodeData } from 'vue';
|
|
||||||
import { FunctionalRenderContext } from 'vue/src/core';
|
|
||||||
|
|
||||||
import { IconifyIcon as IconifyIconData, IconifyJSON } from '@iconify/types';
|
|
||||||
import {
|
|
||||||
IconifyIconCustomisations as IconCustomisations,
|
|
||||||
FullIconCustomisations,
|
|
||||||
defaults,
|
|
||||||
IconifyHorizontalIconAlignment,
|
|
||||||
IconifyVerticalIconAlignment,
|
|
||||||
IconifyIconSize,
|
|
||||||
} from '@iconify/core/lib/customisations';
|
|
||||||
import {
|
|
||||||
flipFromString,
|
|
||||||
alignmentFromString,
|
|
||||||
} from '@iconify/core/lib/customisations/shorthand';
|
|
||||||
import { rotateFromString } from '@iconify/core/lib/customisations/rotate';
|
|
||||||
import { fullIcon } from '@iconify/core/lib/icon';
|
|
||||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
|
||||||
import { replaceIDs } from '@iconify/core/lib/builder/ids';
|
|
||||||
import { merge } from '@iconify/core/lib/misc/merge';
|
|
||||||
import { parseIconSet } from '@iconify/core/lib/icon/icon-set';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export types that could be used in component
|
|
||||||
*/
|
|
||||||
export {
|
|
||||||
IconifyIconData,
|
|
||||||
IconifyJSON,
|
|
||||||
IconifyHorizontalIconAlignment,
|
|
||||||
IconifyVerticalIconAlignment,
|
|
||||||
IconifyIconSize,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allow rotation to be string
|
|
||||||
/**
|
|
||||||
* Icon customisations
|
|
||||||
*/
|
|
||||||
export type IconifyIconCustomisations = IconCustomisations & {
|
|
||||||
rotate?: string | number;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Icon properties
|
|
||||||
*/
|
|
||||||
export interface IconifyIconProps extends IconifyIconCustomisations {
|
|
||||||
icon: IconifyIconData;
|
|
||||||
|
|
||||||
// Style
|
|
||||||
color?: string;
|
|
||||||
|
|
||||||
// Shorthand properties
|
|
||||||
flip?: string;
|
|
||||||
align?: string;
|
|
||||||
|
|
||||||
// Aliases for alignment because "v-align" is treated like directive
|
|
||||||
horizontalAlign?: IconifyHorizontalIconAlignment;
|
|
||||||
verticalAlign?: IconifyVerticalIconAlignment;
|
|
||||||
|
|
||||||
// Aliases for flip because "v-flip" is treated like directive
|
|
||||||
horizontalFlip?: boolean;
|
|
||||||
verticalFlip?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface for functional component context that is missing in Vue types.
|
|
||||||
// Missing some unused stuff: children, slots, scopedSlots, injections
|
|
||||||
// interface FunctionalRenderContext {
|
|
||||||
// props: { [key: string]: unknown };
|
|
||||||
// data?: VNodeData;
|
|
||||||
// parent?: VNode;
|
|
||||||
// listeners?: object; // alias of data.on
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default SVG attributes
|
|
||||||
*/
|
|
||||||
const svgDefaults = {
|
|
||||||
'xmlns': 'http://www.w3.org/2000/svg',
|
|
||||||
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
|
||||||
'aria-hidden': true,
|
|
||||||
'role': 'img',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aliases for customisations.
|
|
||||||
* In Vue 'v-' properties are reserved, so v-align and v-flip must be renamed
|
|
||||||
*/
|
|
||||||
const customisationAliases = {
|
|
||||||
horizontalAlign: 'hAlign',
|
|
||||||
verticalAlign: 'vAlign',
|
|
||||||
horizontalFlip: 'hFlip',
|
|
||||||
verticalFlip: 'vFlip',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Storage for icons referred by name
|
|
||||||
*/
|
|
||||||
const storage: Record<string, Required<IconifyIconData>> = Object.create(null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for style variable
|
|
||||||
*/
|
|
||||||
type VNodeStyle = (string | Record<string, unknown>)[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IconifyIcon component
|
|
||||||
*/
|
|
||||||
const IconifyIcon = {
|
|
||||||
name: 'IconifyIcon',
|
|
||||||
functional: true,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render icon
|
|
||||||
*
|
|
||||||
* @param createElement
|
|
||||||
* @param context
|
|
||||||
*/
|
|
||||||
render(
|
|
||||||
createElement: typeof _Vue.prototype.$createElement,
|
|
||||||
context: FunctionalRenderContext
|
|
||||||
): VNode {
|
|
||||||
const props = context.props;
|
|
||||||
|
|
||||||
// Split properties
|
|
||||||
const icon =
|
|
||||||
typeof props.icon === 'string'
|
|
||||||
? storage[props.icon]
|
|
||||||
: fullIcon(props.icon);
|
|
||||||
if (!icon) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const customisations = merge(
|
|
||||||
defaults,
|
|
||||||
props as IconifyIconCustomisations
|
|
||||||
) as FullIconCustomisations;
|
|
||||||
const componentProps = merge(svgDefaults);
|
|
||||||
|
|
||||||
// Copy style
|
|
||||||
let stylesList: VNodeStyle;
|
|
||||||
let styleString: string;
|
|
||||||
let isStyleString = false;
|
|
||||||
let hasStyle = true;
|
|
||||||
|
|
||||||
function setStyle(value: unknown): boolean {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
// Style as string
|
|
||||||
styleString = value;
|
|
||||||
isStyleString = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (typeof value !== 'object') {
|
|
||||||
// Unknown type ???
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stylesList = value instanceof Array ? value.slice(0) : [value];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextData = context.data;
|
|
||||||
if (
|
|
||||||
!contextData ||
|
|
||||||
(!setStyle(contextData.staticStyle) && !setStyle(contextData.style))
|
|
||||||
) {
|
|
||||||
stylesList = [];
|
|
||||||
hasStyle = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get element properties
|
|
||||||
for (let key in props) {
|
|
||||||
const value = props[key];
|
|
||||||
switch (key) {
|
|
||||||
// Properties to ignore
|
|
||||||
case 'icon':
|
|
||||||
case 'style':
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Flip as string: 'horizontal,vertical'
|
|
||||||
case 'flip':
|
|
||||||
flipFromString(customisations, value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Alignment as string
|
|
||||||
case 'align':
|
|
||||||
alignmentFromString(customisations, value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Color: copy to style
|
|
||||||
case 'color':
|
|
||||||
if (isStyleString) {
|
|
||||||
styleString = 'color: ' + value + '; ' + styleString;
|
|
||||||
} else {
|
|
||||||
stylesList.unshift({
|
|
||||||
color: value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
hasStyle = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Rotation as string
|
|
||||||
case 'rotate':
|
|
||||||
if (typeof value !== 'number') {
|
|
||||||
customisations[key] = rotateFromString(value);
|
|
||||||
} else {
|
|
||||||
componentProps[key] = value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Remove aria-hidden
|
|
||||||
case 'ariaHidden':
|
|
||||||
case 'aria-hidden':
|
|
||||||
// Vue transforms 'aria-hidden' property to 'ariaHidden'
|
|
||||||
if (value !== true && value !== 'true') {
|
|
||||||
delete componentProps['aria-hidden'];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (customisationAliases[key] !== void 0) {
|
|
||||||
// Aliases for customisations
|
|
||||||
customisations[customisationAliases[key]] = value;
|
|
||||||
} else if (defaults[key] === void 0) {
|
|
||||||
// Copy missing property if it does not exist in customisations
|
|
||||||
componentProps[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate icon
|
|
||||||
const item = iconToSVG(icon, customisations);
|
|
||||||
|
|
||||||
// Add icon stuff
|
|
||||||
for (let key in item.attributes) {
|
|
||||||
componentProps[key] = item.attributes[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.inline) {
|
|
||||||
if (isStyleString) {
|
|
||||||
styleString = 'vertical-align: -0.125em; ' + styleString;
|
|
||||||
} else {
|
|
||||||
stylesList.unshift({
|
|
||||||
verticalAlign: '-0.125em',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
hasStyle = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate node data
|
|
||||||
const data: VNodeData = {
|
|
||||||
attrs: componentProps,
|
|
||||||
domProps: {
|
|
||||||
innerHTML: replaceIDs(item.body),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (hasStyle) {
|
|
||||||
data.style = isStyleString ? styleString : stylesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contextData) {
|
|
||||||
['on', 'ref'].forEach((attr) => {
|
|
||||||
if (contextData[attr] !== void 0) {
|
|
||||||
data[attr] = contextData[attr];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
['staticClass', 'class'].forEach((attr) => {
|
|
||||||
if (contextData[attr] !== void 0) {
|
|
||||||
data.class = contextData[attr];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return createElement('svg', data);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add icon to storage that can later be used by name, for example: <iconify-icon icon="home" />
|
|
||||||
*/
|
|
||||||
addIcon: (name: string, data: IconifyIconData) => {
|
|
||||||
storage[name] = fullIcon(data);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add collection to storage, allowing to call icons by name
|
|
||||||
*
|
|
||||||
* @param data Icon set
|
|
||||||
* @param prefix Optional prefix to add to icon names, true if prefix from icon set should be used.
|
|
||||||
*/
|
|
||||||
addCollection: (data: IconifyJSON, prefix?: string | boolean) => {
|
|
||||||
const iconPrefix: string =
|
|
||||||
typeof prefix === 'string'
|
|
||||||
? prefix
|
|
||||||
: prefix !== false && typeof data.prefix === 'string'
|
|
||||||
? data.prefix + ':'
|
|
||||||
: '';
|
|
||||||
parseIconSet(data, (name, icon) => {
|
|
||||||
if (icon !== null) {
|
|
||||||
storage[iconPrefix + name] = icon;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Install function
|
|
||||||
interface InstallFunction extends PluginFunction<unknown> {
|
|
||||||
installed?: boolean;
|
|
||||||
}
|
|
||||||
interface InstallableComponent extends VueConstructor<_Vue> {
|
|
||||||
install: InstallFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
const install: InstallFunction = function installIconifyIcon(Vue: typeof _Vue) {
|
|
||||||
if (install.installed) return;
|
|
||||||
install.installed = true;
|
|
||||||
Vue.component('IconifyIcon', IconifyIcon);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create module definition for Vue.use()
|
|
||||||
const plugin = {
|
|
||||||
install,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Auto-install when vue is found (eg. in browser via <script> tag)
|
|
||||||
let GlobalVue = null;
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
GlobalVue = window.Vue;
|
|
||||||
} else if (typeof global !== 'undefined') {
|
|
||||||
GlobalVue = ((global as unknown) as Record<string, unknown>).Vue;
|
|
||||||
}
|
|
||||||
if (GlobalVue) {
|
|
||||||
GlobalVue.use(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inject install function into component - allows component
|
|
||||||
// to be registered via Vue.use() as well as Vue.component()
|
|
||||||
((IconifyIcon as unknown) as InstallableComponent).install = install;
|
|
||||||
|
|
||||||
// Export component
|
|
||||||
export default IconifyIcon;
|
|
114
packages/vue2/src/iconify.ts
Normal file
114
packages/vue2/src/iconify.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import Vue, { CreateElement, VNode } from 'vue';
|
||||||
|
import { ExtendedVue } from 'vue/types/vue';
|
||||||
|
import { IconifyIcon, IconifyJSON } from '@iconify/types';
|
||||||
|
import {
|
||||||
|
IconifyHorizontalIconAlignment,
|
||||||
|
IconifyVerticalIconAlignment,
|
||||||
|
IconifyIconSize,
|
||||||
|
} from '@iconify/core/lib/customisations';
|
||||||
|
import { fullIcon } from '@iconify/core/lib/icon';
|
||||||
|
import { parseIconSet } from '@iconify/core/lib/icon/icon-set';
|
||||||
|
import {
|
||||||
|
IconifyIconCustomisations,
|
||||||
|
IconifyIconProps,
|
||||||
|
IconProps,
|
||||||
|
} from './props';
|
||||||
|
import { render } from './render';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export stuff from props.ts
|
||||||
|
*/
|
||||||
|
export { IconifyIconCustomisations, IconifyIconProps, IconProps };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export types that could be used in component
|
||||||
|
*/
|
||||||
|
export {
|
||||||
|
IconifyIcon,
|
||||||
|
IconifyJSON,
|
||||||
|
IconifyHorizontalIconAlignment,
|
||||||
|
IconifyVerticalIconAlignment,
|
||||||
|
IconifyIconSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Storage for icons referred by name
|
||||||
|
*/
|
||||||
|
const storage: Record<string, Required<IconifyIcon>> = Object.create(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add icon to storage, allowing to call it by name
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export function addIcon(name: string, data: IconifyIcon): void {
|
||||||
|
storage[name] = fullIcon(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add collection to storage, allowing to call icons by name
|
||||||
|
*
|
||||||
|
* @param data Icon set
|
||||||
|
* @param prefix Optional prefix to add to icon names, true (default) if prefix from icon set should be used.
|
||||||
|
*/
|
||||||
|
export function addCollection(
|
||||||
|
data: IconifyJSON,
|
||||||
|
prefix?: string | boolean
|
||||||
|
): void {
|
||||||
|
const iconPrefix: string =
|
||||||
|
typeof prefix === 'string'
|
||||||
|
? prefix
|
||||||
|
: prefix !== false && typeof data.prefix === 'string'
|
||||||
|
? data.prefix + ':'
|
||||||
|
: '';
|
||||||
|
parseIconSet(data, (name, icon) => {
|
||||||
|
if (icon !== null) {
|
||||||
|
storage[iconPrefix + name] = icon;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component
|
||||||
|
*/
|
||||||
|
export const Icon = Vue.extend({
|
||||||
|
// Do not inherit other attributes: it is handled by render()
|
||||||
|
// In Vue 2 style is still passed!
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
// Render icon
|
||||||
|
render(createElement: CreateElement): VNode {
|
||||||
|
const props = this.$attrs;
|
||||||
|
|
||||||
|
// Check icon
|
||||||
|
const icon =
|
||||||
|
typeof props.icon === 'string'
|
||||||
|
? storage[props.icon]
|
||||||
|
: typeof props.icon === 'object'
|
||||||
|
? fullIcon(props.icon)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Validate icon object
|
||||||
|
if (
|
||||||
|
icon === null ||
|
||||||
|
typeof icon !== 'object' ||
|
||||||
|
typeof icon.body !== 'string'
|
||||||
|
) {
|
||||||
|
// Render child nodes
|
||||||
|
if (this.$slots.default) {
|
||||||
|
const result = this.$slots.default;
|
||||||
|
if (result instanceof Array && result.length > 0) {
|
||||||
|
// If there are multiple child nodes, they must be wrapped in Vue 2
|
||||||
|
return result.length === 1
|
||||||
|
? result[0]
|
||||||
|
: createElement('span', result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (null as unknown) as VNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid icon: render it
|
||||||
|
return render(createElement, props, this.$data, icon);
|
||||||
|
},
|
||||||
|
});
|
114
packages/vue2/src/offline.ts
Normal file
114
packages/vue2/src/offline.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import Vue, { CreateElement, VNode } from 'vue';
|
||||||
|
import { ExtendedVue } from 'vue/types/vue';
|
||||||
|
import { IconifyIcon, IconifyJSON } from '@iconify/types';
|
||||||
|
import {
|
||||||
|
IconifyHorizontalIconAlignment,
|
||||||
|
IconifyVerticalIconAlignment,
|
||||||
|
IconifyIconSize,
|
||||||
|
} from '@iconify/core/lib/customisations';
|
||||||
|
import { fullIcon } from '@iconify/core/lib/icon';
|
||||||
|
import { parseIconSet } from '@iconify/core/lib/icon/icon-set';
|
||||||
|
import {
|
||||||
|
IconifyIconCustomisations,
|
||||||
|
IconifyIconProps,
|
||||||
|
IconProps,
|
||||||
|
} from './props';
|
||||||
|
import { render } from './render';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export stuff from props.ts
|
||||||
|
*/
|
||||||
|
export { IconifyIconCustomisations, IconifyIconProps, IconProps };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export types that could be used in component
|
||||||
|
*/
|
||||||
|
export {
|
||||||
|
IconifyIcon,
|
||||||
|
IconifyJSON,
|
||||||
|
IconifyHorizontalIconAlignment,
|
||||||
|
IconifyVerticalIconAlignment,
|
||||||
|
IconifyIconSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Storage for icons referred by name
|
||||||
|
*/
|
||||||
|
const storage: Record<string, Required<IconifyIcon>> = Object.create(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add icon to storage, allowing to call it by name
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export function addIcon(name: string, data: IconifyIcon): void {
|
||||||
|
storage[name] = fullIcon(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add collection to storage, allowing to call icons by name
|
||||||
|
*
|
||||||
|
* @param data Icon set
|
||||||
|
* @param prefix Optional prefix to add to icon names, true (default) if prefix from icon set should be used.
|
||||||
|
*/
|
||||||
|
export function addCollection(
|
||||||
|
data: IconifyJSON,
|
||||||
|
prefix?: string | boolean
|
||||||
|
): void {
|
||||||
|
const iconPrefix: string =
|
||||||
|
typeof prefix === 'string'
|
||||||
|
? prefix
|
||||||
|
: prefix !== false && typeof data.prefix === 'string'
|
||||||
|
? data.prefix + ':'
|
||||||
|
: '';
|
||||||
|
parseIconSet(data, (name, icon) => {
|
||||||
|
if (icon !== null) {
|
||||||
|
storage[iconPrefix + name] = icon;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component
|
||||||
|
*/
|
||||||
|
export const Icon = Vue.extend({
|
||||||
|
// Do not inherit other attributes: it is handled by render()
|
||||||
|
// In Vue 2 style is still passed!
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
// Render icon
|
||||||
|
render(createElement: CreateElement): VNode {
|
||||||
|
const props = this.$attrs;
|
||||||
|
|
||||||
|
// Check icon
|
||||||
|
const icon =
|
||||||
|
typeof props.icon === 'string'
|
||||||
|
? storage[props.icon]
|
||||||
|
: typeof props.icon === 'object'
|
||||||
|
? fullIcon(props.icon)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// Validate icon object
|
||||||
|
if (
|
||||||
|
icon === null ||
|
||||||
|
typeof icon !== 'object' ||
|
||||||
|
typeof icon.body !== 'string'
|
||||||
|
) {
|
||||||
|
// Render child nodes
|
||||||
|
if (this.$slots.default) {
|
||||||
|
const result = this.$slots.default;
|
||||||
|
if (result instanceof Array && result.length > 0) {
|
||||||
|
// If there are multiple child nodes, they must be wrapped in Vue 2
|
||||||
|
return result.length === 1
|
||||||
|
? result[0]
|
||||||
|
: createElement('span', result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (null as unknown) as VNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid icon: render it
|
||||||
|
return render(createElement, props, this.$data, icon);
|
||||||
|
},
|
||||||
|
});
|
41
packages/vue2/src/props.ts
Normal file
41
packages/vue2/src/props.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { IconifyIcon } from '@iconify/types';
|
||||||
|
import { IconifyIconCustomisations as IconCustomisations } from '@iconify/core/lib/customisations';
|
||||||
|
|
||||||
|
// Allow rotation to be string
|
||||||
|
/**
|
||||||
|
* Icon customisations
|
||||||
|
*/
|
||||||
|
export type IconifyIconCustomisations = IconCustomisations & {
|
||||||
|
rotate?: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon properties
|
||||||
|
*/
|
||||||
|
export interface IconifyIconProps extends IconifyIconCustomisations {
|
||||||
|
// Icon object
|
||||||
|
icon: IconifyIcon | string;
|
||||||
|
|
||||||
|
// Style
|
||||||
|
color?: string;
|
||||||
|
|
||||||
|
// Shorthand properties
|
||||||
|
flip?: string;
|
||||||
|
align?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for element that are mentioned in render.ts
|
||||||
|
*/
|
||||||
|
interface IconifyElementProps {
|
||||||
|
// Unique id, used as base for ids for shapes. Use it to get consistent ids for server side rendering
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
// Style
|
||||||
|
style?: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mix of icon properties and HTMLElement properties
|
||||||
|
*/
|
||||||
|
export type IconProps = IconifyElementProps & IconifyIconProps;
|
178
packages/vue2/src/render.ts
Normal file
178
packages/vue2/src/render.ts
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
import _Vue, { VNode, VNodeData, RenderContext } from 'vue';
|
||||||
|
import { IconifyIcon } from '@iconify/types';
|
||||||
|
import {
|
||||||
|
FullIconCustomisations,
|
||||||
|
defaults,
|
||||||
|
} from '@iconify/core/lib/customisations';
|
||||||
|
import {
|
||||||
|
flipFromString,
|
||||||
|
alignmentFromString,
|
||||||
|
} from '@iconify/core/lib/customisations/shorthand';
|
||||||
|
import { rotateFromString } from '@iconify/core/lib/customisations/rotate';
|
||||||
|
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||||
|
import { replaceIDs } from '@iconify/core/lib/builder/ids';
|
||||||
|
import { merge } from '@iconify/core/lib/misc/merge';
|
||||||
|
import { IconifyIconCustomisations, IconProps } from './props';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default SVG attributes
|
||||||
|
*/
|
||||||
|
const svgDefaults: Record<string, unknown> = {
|
||||||
|
'xmlns': 'http://www.w3.org/2000/svg',
|
||||||
|
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
||||||
|
'aria-hidden': true,
|
||||||
|
'role': 'img',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aliases for customisations.
|
||||||
|
* In Vue 'v-' properties are reserved, so v-align and v-flip must be renamed
|
||||||
|
*/
|
||||||
|
let customisationAliases = {};
|
||||||
|
['horizontal', 'vertical'].forEach((prefix) => {
|
||||||
|
['Align', 'Flip'].forEach((suffix) => {
|
||||||
|
const attr = prefix.slice(0, 1) + suffix;
|
||||||
|
// vertical-align
|
||||||
|
customisationAliases[prefix + '-' + suffix.toLowerCase()] = attr;
|
||||||
|
// v-align
|
||||||
|
customisationAliases[
|
||||||
|
prefix.slice(0, 1) + '-' + suffix.toLowerCase()
|
||||||
|
] = attr;
|
||||||
|
// verticalAlign
|
||||||
|
customisationAliases[prefix + suffix] = attr;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for inline style
|
||||||
|
*/
|
||||||
|
type VNodeStyle = (string | Record<string, unknown>)[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render icon
|
||||||
|
*/
|
||||||
|
export const render = (
|
||||||
|
createElement: typeof _Vue.prototype.$createElement,
|
||||||
|
|
||||||
|
// context.props
|
||||||
|
props: IconProps,
|
||||||
|
|
||||||
|
// context.data
|
||||||
|
contextData: VNodeData,
|
||||||
|
|
||||||
|
// Icon must be validated before calling this function
|
||||||
|
icon: Required<IconifyIcon>
|
||||||
|
): VNode => {
|
||||||
|
// Split properties
|
||||||
|
const customisations = merge(
|
||||||
|
defaults,
|
||||||
|
props as IconifyIconCustomisations
|
||||||
|
) as FullIconCustomisations;
|
||||||
|
const componentProps = merge(svgDefaults);
|
||||||
|
|
||||||
|
// Style in Vue 2 components is always passed to rendered component, so no point in parsing it
|
||||||
|
const style: Record<string, unknown> = {};
|
||||||
|
|
||||||
|
// Get element properties
|
||||||
|
for (let key in props) {
|
||||||
|
const value = props[key];
|
||||||
|
switch (key) {
|
||||||
|
// Properties to ignore
|
||||||
|
case 'icon':
|
||||||
|
case 'style':
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Flip as string: 'horizontal,vertical'
|
||||||
|
case 'flip':
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
flipFromString(customisations, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Alignment as string
|
||||||
|
case 'align':
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
alignmentFromString(customisations, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Color: override style
|
||||||
|
case 'color':
|
||||||
|
style.color = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Rotation as string
|
||||||
|
case 'rotate':
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
customisations[key] = rotateFromString(value);
|
||||||
|
} else if (typeof value === 'number') {
|
||||||
|
customisations[key] = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Remove aria-hidden
|
||||||
|
case 'ariaHidden':
|
||||||
|
case 'aria-hidden':
|
||||||
|
// Vue transforms 'aria-hidden' property to 'ariaHidden'
|
||||||
|
if (value !== true && value !== 'true') {
|
||||||
|
delete componentProps['aria-hidden'];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (customisationAliases[key] !== void 0) {
|
||||||
|
// Aliases for customisations
|
||||||
|
customisations[customisationAliases[key]] = value;
|
||||||
|
} else if (defaults[key] === void 0) {
|
||||||
|
// Copy missing property if it does not exist in customisations
|
||||||
|
componentProps[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate icon
|
||||||
|
const item = iconToSVG(icon, customisations);
|
||||||
|
|
||||||
|
// Add icon stuff
|
||||||
|
for (let key in item.attributes) {
|
||||||
|
componentProps[key] = item.attributes[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.inline) {
|
||||||
|
style.verticalAlign = '-0.125em';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counter for ids based on "id" property to render icons consistently on server and client
|
||||||
|
let localCounter = 0;
|
||||||
|
const id = props.id;
|
||||||
|
|
||||||
|
// Generate node data
|
||||||
|
const data: VNodeData = {
|
||||||
|
attrs: componentProps,
|
||||||
|
domProps: {
|
||||||
|
innerHTML: replaceIDs(
|
||||||
|
item.body,
|
||||||
|
id ? () => id + '-' + localCounter++ : 'iconify-vue-'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (Object.keys(style).length > 0) {
|
||||||
|
data.style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contextData) {
|
||||||
|
['on', 'ref'].forEach((attr) => {
|
||||||
|
if (contextData[attr] !== void 0) {
|
||||||
|
data[attr] = contextData[attr];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
['staticClass', 'class'].forEach((attr) => {
|
||||||
|
if (contextData[attr] !== void 0) {
|
||||||
|
data.class = contextData[attr];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render icon
|
||||||
|
return createElement('svg', data);
|
||||||
|
};
|
@ -1,570 +0,0 @@
|
|||||||
import { mount } from '@vue/test-utils';
|
|
||||||
import IconifyIcon from '../';
|
|
||||||
|
|
||||||
const iconData = {
|
|
||||||
body:
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
};
|
|
||||||
|
|
||||||
const iconDataWithID = {
|
|
||||||
body:
|
|
||||||
'<defs><path id="ssvg-id-1st-place-medala" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medald" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalf" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalh" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalj" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalm" d="M.93.01h120.55v58.36H.93z"/><path d="M52.849 78.373v-3.908c3.681-.359 6.25-.958 7.703-1.798c1.454-.84 2.54-2.828 3.257-5.962h4.021v40.385h-5.437V78.373h-9.544z" id="ssvg-id-1st-place-medalp"/><linearGradient x1="49.998%" y1="-13.249%" x2="49.998%" y2="90.002%" id="ssvg-id-1st-place-medalb"><stop stop-color="#1E88E5" offset="13.55%"/><stop stop-color="#1565C0" offset="93.8%"/></linearGradient><linearGradient x1="26.648%" y1="2.735%" x2="77.654%" y2="105.978%" id="ssvg-id-1st-place-medalk"><stop stop-color="#64B5F6" offset="13.55%"/><stop stop-color="#2196F3" offset="94.62%"/></linearGradient><radialGradient cx="22.368%" cy="12.5%" fx="22.368%" fy="12.5%" r="95.496%" id="ssvg-id-1st-place-medalo"><stop stop-color="#FFEB3B" offset="29.72%"/><stop stop-color="#FBC02D" offset="95.44%"/></radialGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medalc" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medala"/></mask><path fill="url(#ssvg-id-1st-place-medalb)" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medalc)" d="M45.44 42.18h31.43l30-48.43H75.44z"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medale" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medald"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medale)" fill="#424242" fill-rule="nonzero"><path d="M101.23-3L75.2 39H50.85L77.11-3h24.12zm5.64-3H75.44l-30 48h31.42l30.01-48z"/></g></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medalg" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalf"/></mask><path d="M79 30H43c-4.42 0-8 3.58-8 8v16.04c0 2.17 1.8 3.95 4.02 3.96h.01c2.23-.01 4.97-1.75 4.97-3.96V44c0-1.1.9-2 2-2h30c1.1 0 2 .9 2 2v9.93c0 1.98 2.35 3.68 4.22 4.04c.26.05.52.08.78.08c2.21 0 4-1.79 4-4V38c0-4.42-3.58-8-8-8z" fill="#FDD835" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medalg)"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medali" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalh"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medali)" fill="#424242" fill-rule="nonzero"><path d="M79 32c3.31 0 6 2.69 6 6v16.04A2.006 2.006 0 0 1 82.59 56c-1.18-.23-2.59-1.35-2.59-2.07V44c0-2.21-1.79-4-4-4H46c-2.21 0-4 1.79-4 4v10.04c0 .88-1.64 1.96-2.97 1.96c-1.12-.01-2.03-.89-2.03-1.96V38c0-3.31 2.69-6 6-6h36zm0-2H43c-4.42 0-8 3.58-8 8v16.04c0 2.17 1.8 3.95 4.02 3.96h.01c2.23-.01 4.97-1.75 4.97-3.96V44c0-1.1.9-2 2-2h30c1.1 0 2 .9 2 2v9.93c0 1.98 2.35 3.68 4.22 4.04c.26.05.52.08.78.08c2.21 0 4-1.79 4-4V38c0-4.42-3.58-8-8-8z"/></g></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medall" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalj"/></mask><path fill="url(#ssvg-id-1st-place-medalk)" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medall)" d="M76.87 42.18H45.44l-30-48.43h31.43z"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medaln" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalm"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medaln)" fill="#424242" fill-rule="nonzero"><path d="M45.1-3l26.35 42H47.1L20.86-3H45.1zm1.77-3H15.44l30 48h31.42L46.87-6z"/></g></g><circle fill="url(#ssvg-id-1st-place-medalo)" fill-rule="nonzero" cx="64" cy="86" r="38"/><path d="M64 51c19.3 0 35 15.7 35 35s-15.7 35-35 35s-35-15.7-35-35s15.7-35 35-35zm0-3c-20.99 0-38 17.01-38 38s17.01 38 38 38s38-17.01 38-38s-17.01-38-38-38z" opacity=".2" fill="#424242" fill-rule="nonzero"/><path d="M47.3 63.59h33.4v44.4H47.3z"/><use fill="#000" xlink:href="#ssvg-id-1st-place-medalp"/><use fill="#FFA000" xlink:href="#ssvg-id-1st-place-medalp"/></g>',
|
|
||||||
width: 128,
|
|
||||||
height: 128,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Spacing for HTML matches
|
|
||||||
const spacing = (count) => {
|
|
||||||
return '\n' + ' '.repeat(count);
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Mounting component', () => {
|
|
||||||
test('with wrapper', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon />`,
|
|
||||||
};
|
|
||||||
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('without wrapper', () => {
|
|
||||||
const wrapper = mount(IconifyIcon, {});
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<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 16 16"></svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Rendering icon', () => {
|
|
||||||
test('as object', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<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">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('as string', () => {
|
|
||||||
const iconName = 'test-string';
|
|
||||||
IconifyIcon.addIcon(iconName, iconData);
|
|
||||||
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconName,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<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">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('as string with icon set', () => {
|
|
||||||
const iconSet = {
|
|
||||||
prefix: 'mdi-light',
|
|
||||||
icons: {
|
|
||||||
account: {
|
|
||||||
body:
|
|
||||||
'<path d="M11.5 14c4.142 0 7.5 1.567 7.5 3.5V20H4v-2.5c0-1.933 3.358-3.5 7.5-3.5zm6.5 3.5c0-1.38-2.91-2.5-6.5-2.5S5 16.12 5 17.5V19h13v-1.5zM11.5 5a3.5 3.5 0 1 1 0 7a3.5 3.5 0 0 1 0-7zm0 1a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5z" fill="currentColor"/>',
|
|
||||||
},
|
|
||||||
home: {
|
|
||||||
body:
|
|
||||||
'<path d="M16 8.414l-4.5-4.5L4.414 11H6v8h3v-6h5v6h3v-8h1.586L17 9.414V6h-1v2.414zM2 12l9.5-9.5L15 6V5h3v4l3 3h-3v7.998h-5v-6h-3v6H5V12H2z" fill="currentColor"/>',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
};
|
|
||||||
|
|
||||||
IconifyIcon.addCollection(iconSet);
|
|
||||||
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon icon='mdi-light:home' />`,
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<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">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M16 8.414l-4.5-4.5L4.414 11H6v8h3v-6h5v6h3v-8h1.586L17 9.414V6h-1v2.414zM2 12l9.5-9.5L15 6V5h3v4l3 3h-3v7.998h-5v-6h-3v6H5V12H2z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('as string with icon set with custom prefix', () => {
|
|
||||||
const iconSet = {
|
|
||||||
prefix: 'mdi-light',
|
|
||||||
icons: {
|
|
||||||
'account-alert': {
|
|
||||||
body:
|
|
||||||
'<path d="M10.5 14c4.142 0 7.5 1.567 7.5 3.5V20H3v-2.5c0-1.933 3.358-3.5 7.5-3.5zm6.5 3.5c0-1.38-2.91-2.5-6.5-2.5S4 16.12 4 17.5V19h13v-1.5zM10.5 5a3.5 3.5 0 1 1 0 7a3.5 3.5 0 0 1 0-7zm0 1a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5zM20 16v-1h1v1h-1zm0-3V7h1v6h-1z" fill="currentColor"/>',
|
|
||||||
},
|
|
||||||
'link': {
|
|
||||||
body:
|
|
||||||
'<path d="M8 13v-1h7v1H8zm7.5-6a5.5 5.5 0 1 1 0 11H13v-1h2.5a4.5 4.5 0 1 0 0-9H13V7h2.5zm-8 11a5.5 5.5 0 1 1 0-11H10v1H7.5a4.5 4.5 0 1 0 0 9H10v1H7.5z" fill="currentColor"/>',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
};
|
|
||||||
|
|
||||||
IconifyIcon.addCollection(iconSet, 'custom-');
|
|
||||||
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon icon='custom-link' />`,
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<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">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M8 13v-1h7v1H8zm7.5-6a5.5 5.5 0 1 1 0 11H13v-1h2.5a4.5 4.5 0 1 0 0-9H13V7h2.5zm-8 11a5.5 5.5 0 1 1 0-11H10v1H7.5a4.5 4.5 0 1 0 0 9H10v1H7.5z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('replacing id', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconDataWithID,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).not.toMatch('id="ssvg-id-1st-place-medala"');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Passing attributes', () => {
|
|
||||||
test('title', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' title='Icon!' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" title="Icon!" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('aria-hidden', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :aria-hidden='false' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('ariaHidden', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :ariaHidden='false' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('attributes that cannot change', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' viewBox='0 0 0 0' preserveAspectRatio='none' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
// same values, but different order
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" viewBox="0 0 24 24" preserveAspectRatio="xMidYMid meet" width="1em" height="1em">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Dimensions', () => {
|
|
||||||
test('height', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :height='height' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
height: 24,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="24" height="24" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('width and height', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :width='width' :height='height' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
width: 32, // as number
|
|
||||||
height: '48', // as string
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="32" height="48" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('auto', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :height='height' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
height: 'auto',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toStrictEqual(
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="24" height="24" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">' +
|
|
||||||
spacing(1) +
|
|
||||||
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path>' +
|
|
||||||
spacing(0) +
|
|
||||||
'</svg>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Rotation', () => {
|
|
||||||
test('number', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :rotate='rotate' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
rotate: 1,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('rotate(90 ');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('string', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' rotate='270deg' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('rotate(-90 ');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Flip', () => {
|
|
||||||
test('boolean', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :horizontalFlip='horizontalFlip' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
horizontalFlip: true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('scale(-1 1)');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('string', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' flip='vertical' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('scale(1 -1)');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('string and boolean', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' flip='horizontal' :verticalFlip='true' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
// horizontal + vertical = 180deg rotation
|
|
||||||
expect(item.html()).toMatch('rotate(180 ');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('string for boolean attribute', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' horizontalFlip='true' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('scale(-1 1)');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('shorthand and boolean', () => {
|
|
||||||
// 'flip' is processed after 'hFlip', overwriting value
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' flip='horizontal' :hFlip='false' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('scale(-1 1)');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('shorthand and boolean as string', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' flip='vertical' horizontalFlip='true' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
// horizontal + vertical = 180deg rotation
|
|
||||||
expect(item.html()).toMatch('rotate(180 ');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('wrong case', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' :verticalflip='verticalflip' :horizontalflip='true' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
verticalflip: true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).not.toMatch('scale(');
|
|
||||||
expect(item.html()).not.toMatch('rotate(');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Alignment and slice', () => {
|
|
||||||
test('vAlign and slice', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' vAlign='top' :slice='true' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('preserveAspectRatio="xMidYMin slice"');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('string', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' align='left bottom' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('preserveAspectRatio="xMinYMax meet"');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Alignment aliases', () => {
|
|
||||||
const Wrapper = {
|
|
||||||
components: { IconifyIcon },
|
|
||||||
template: `<iconify-icon :icon='icon' verticalAlign='top' horizontalAlign='right' />`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
icon: iconData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = mount(Wrapper, {});
|
|
||||||
|
|
||||||
const item = wrapper.findComponent(IconifyIcon);
|
|
||||||
expect(item.exists()).toBe(true);
|
|
||||||
expect(item.html()).toMatch('preserveAspectRatio="xMaxYMin meet"');
|
|
||||||
});
|
|
||||||
});
|
|
40
packages/vue2/tests/iconify/10-basic.test.js
Normal file
40
packages/vue2/tests/iconify/10-basic.test.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Creating component', () => {
|
||||||
|
test('with wrapper', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon='icon' />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
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>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('without wrapper', () => {
|
||||||
|
const wrapper = mount(Icon, {
|
||||||
|
propsData: {
|
||||||
|
icon: iconData,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
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>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
46
packages/vue2/tests/iconify/10-empty.test.js
Normal file
46
packages/vue2/tests/iconify/10-empty.test.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { Icon } from '../../dist/iconify';
|
||||||
|
|
||||||
|
describe('Empty icon', () => {
|
||||||
|
test('basic test', () => {
|
||||||
|
const wrapper = mount(Icon, {
|
||||||
|
propsData: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with child node', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon><i class="fa fa-home" /></Icon>`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||||
|
'<i class="fa fa-home"></i>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with text child node', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon>icon</Icon>`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.text()).toEqual('icon');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with multiple childen', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon><i class="fa fa-home" /> Home icon</Icon>`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||||
|
'<span><i class="fa fa-home"></i> Home icon</span>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
144
packages/vue2/tests/iconify/20-attributes.test.js
Normal file
144
packages/vue2/tests/iconify/20-attributes.test.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Passing attributes', () => {
|
||||||
|
test('title', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" title="Icon!" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('role="img" title="Icon!"');
|
||||||
|
|
||||||
|
// Make sure aria-hidden exists (for tests below)
|
||||||
|
expect(html).toContain('aria-hidden="true"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('aria-hidden', () => {
|
||||||
|
// dashes, string value
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" aria-hidden="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('aria-hidden="true"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ariaHidden', () => {
|
||||||
|
// camelCase, boolean value
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :ariaHidden="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('aria-hidden="true"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('style as string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" style="color: red;" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: red;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('style as object', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :style="style" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
style: {
|
||||||
|
color: 'red',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: red;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('color', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" color="red" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: red;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('color with style', () => {
|
||||||
|
// In Vue 2 style overrides color in class components
|
||||||
|
// Can be fixed by using functional component, but functional component is not possible with API
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" color="purple" style="color: green;" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: green;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('attributes that cannot change', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" viewBox="0 0 0 0" preserveAspectRatio="none" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).not.toContain('viewBox="0 0 0 0"');
|
||||||
|
expect(html).not.toContain('preserveAspectRatio="none"');
|
||||||
|
});
|
||||||
|
});
|
68
packages/vue2/tests/iconify/20-dimensions.test.js
Normal file
68
packages/vue2/tests/iconify/20-dimensions.test.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Dimensions', () => {
|
||||||
|
test('height', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" height="48" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('height="48"');
|
||||||
|
expect(html).toContain('width="48"');
|
||||||
|
expect(html).not.toContain('height="1em"');
|
||||||
|
expect(html).not.toContain('width="1em"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('width and height', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :width="32" height="48" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('height="48"');
|
||||||
|
expect(html).toContain('width="32"');
|
||||||
|
expect(html).not.toContain('height="1em"');
|
||||||
|
expect(html).not.toContain('width="1em"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('auto', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" height="auto" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('height="24"');
|
||||||
|
expect(html).toContain('width="24"');
|
||||||
|
expect(html).not.toContain('height="1em"');
|
||||||
|
expect(html).not.toContain('width="1em"');
|
||||||
|
});
|
||||||
|
});
|
41
packages/vue2/tests/iconify/20-ids.test.js
Normal file
41
packages/vue2/tests/iconify/20-ids.test.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { Icon } from '../../dist/iconify';
|
||||||
|
|
||||||
|
const iconDataWithID = {
|
||||||
|
body:
|
||||||
|
'<defs><path id="ssvg-id-1st-place-medala" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medald" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalf" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalh" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalj" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalm" d="M.93.01h120.55v58.36H.93z"/><path d="M52.849 78.373v-3.908c3.681-.359 6.25-.958 7.703-1.798c1.454-.84 2.54-2.828 3.257-5.962h4.021v40.385h-5.437V78.373h-9.544z" id="ssvg-id-1st-place-medalp"/><linearGradient x1="49.998%" y1="-13.249%" x2="49.998%" y2="90.002%" id="ssvg-id-1st-place-medalb"><stop stop-color="#1E88E5" offset="13.55%"/><stop stop-color="#1565C0" offset="93.8%"/></linearGradient><linearGradient x1="26.648%" y1="2.735%" x2="77.654%" y2="105.978%" id="ssvg-id-1st-place-medalk"><stop stop-color="#64B5F6" offset="13.55%"/><stop stop-color="#2196F3" offset="94.62%"/></linearGradient><radialGradient cx="22.368%" cy="12.5%" fx="22.368%" fy="12.5%" r="95.496%" id="ssvg-id-1st-place-medalo"><stop stop-color="#FFEB3B" offset="29.72%"/><stop stop-color="#FBC02D" offset="95.44%"/></radialGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medalc" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medala"/></mask><path fill="url(#ssvg-id-1st-place-medalb)" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medalc)" d="M45.44 42.18h31.43l30-48.43H75.44z"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medale" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medald"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medale)" fill="#424242" fill-rule="nonzero"><path d="M101.23-3L75.2 39H50.85L77.11-3h24.12zm5.64-3H75.44l-30 48h31.42l30.01-48z"/></g></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medalg" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalf"/></mask><path d="M79 30H43c-4.42 0-8 3.58-8 8v16.04c0 2.17 1.8 3.95 4.02 3.96h.01c2.23-.01 4.97-1.75 4.97-3.96V44c0-1.1.9-2 2-2h30c1.1 0 2 .9 2 2v9.93c0 1.98 2.35 3.68 4.22 4.04c.26.05.52.08.78.08c2.21 0 4-1.79 4-4V38c0-4.42-3.58-8-8-8z" fill="#FDD835" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medalg)"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medali" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalh"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medali)" fill="#424242" fill-rule="nonzero"><path d="M79 32c3.31 0 6 2.69 6 6v16.04A2.006 2.006 0 0 1 82.59 56c-1.18-.23-2.59-1.35-2.59-2.07V44c0-2.21-1.79-4-4-4H46c-2.21 0-4 1.79-4 4v10.04c0 .88-1.64 1.96-2.97 1.96c-1.12-.01-2.03-.89-2.03-1.96V38c0-3.31 2.69-6 6-6h36zm0-2H43c-4.42 0-8 3.58-8 8v16.04c0 2.17 1.8 3.95 4.02 3.96h.01c2.23-.01 4.97-1.75 4.97-3.96V44c0-1.1.9-2 2-2h30c1.1 0 2 .9 2 2v9.93c0 1.98 2.35 3.68 4.22 4.04c.26.05.52.08.78.08c2.21 0 4-1.79 4-4V38c0-4.42-3.58-8-8-8z"/></g></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medall" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalj"/></mask><path fill="url(#ssvg-id-1st-place-medalk)" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medall)" d="M76.87 42.18H45.44l-30-48.43h31.43z"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medaln" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalm"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medaln)" fill="#424242" fill-rule="nonzero"><path d="M45.1-3l26.35 42H47.1L20.86-3H45.1zm1.77-3H15.44l30 48h31.42L46.87-6z"/></g></g><circle fill="url(#ssvg-id-1st-place-medalo)" fill-rule="nonzero" cx="64" cy="86" r="38"/><path d="M64 51c19.3 0 35 15.7 35 35s-15.7 35-35 35s-35-15.7-35-35s15.7-35 35-35zm0-3c-20.99 0-38 17.01-38 38s17.01 38 38 38s38-17.01 38-38s-17.01-38-38-38z" opacity=".2" fill="#424242" fill-rule="nonzero"/><path d="M47.3 63.59h33.4v44.4H47.3z"/><use fill="#000" xlink:href="#ssvg-id-1st-place-medalp"/><use fill="#FFA000" xlink:href="#ssvg-id-1st-place-medalp"/></g>',
|
||||||
|
width: 128,
|
||||||
|
height: 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Replacing IDs', () => {
|
||||||
|
test('default behavior', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconDataWithID,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('ssvg-id-1st-place-medala');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('custom generator', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" id="test" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconDataWithID,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('id="test-0"');
|
||||||
|
});
|
||||||
|
});
|
135
packages/vue2/tests/iconify/20-inline.test.js
Normal file
135
packages/vue2/tests/iconify/20-inline.test.js
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Inline attribute', () => {
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" inline="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('false string', () => {
|
||||||
|
// "false" = true
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" inline="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('true', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('false', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain(
|
||||||
|
'vertical-align: -0.125em; color: red;'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('inline and style string', () => {
|
||||||
|
// Style goes after vertical-align
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" style="color: red;" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'vertical-align: -0.125em; color: red;'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('inline and style object', () => {
|
||||||
|
// Style goes after vertical-align
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" :style="style" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
style: {
|
||||||
|
color: 'red',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'vertical-align: -0.125em; color: red;'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('inline and style overriding it', () => {
|
||||||
|
// Style goes after vertical-align
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" :style="style" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
style: {
|
||||||
|
verticalAlign: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
// For some reason style is duplicated
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'style="vertical-align: 0; vertical-align: 0;"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
208
packages/vue2/tests/iconify/20-transformations.test.js
Normal file
208
packages/vue2/tests/iconify/20-transformations.test.js
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Rotation', () => {
|
||||||
|
test('number', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :rotate="1" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
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"><g transform="rotate(90 12 12)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" rotate="180deg" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('<g transform="rotate(180 12 12)">');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Flip', () => {
|
||||||
|
test('boolean', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :hFlip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(24 0) scale(-1 1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="vertical" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(0 24) scale(1 -1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string and boolean', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="horizontal" :vFlip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('<g transform="rotate(180 12 12)">');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string for boolean attribute', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" horizontal-flip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(24 0) scale(-1 1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('shorthand and boolean', () => {
|
||||||
|
// 'flip' is processed after 'hFlip', overwriting value
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="horizontal" :hFlip="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(24 0) scale(-1 1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('shorthand and boolean as string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="vertical" :horizontal-flip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('<g transform="rotate(180 12 12)">');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('wrong case', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :vflip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('<g transform="');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Alignment and slice', () => {
|
||||||
|
test('vAlign and slice', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" vAlign="top" :slice="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'preserveAspectRatio="xMidYMin slice"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" align="left bottom" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('preserveAspectRatio="xMinYMax meet"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('aliases', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" h-align="left" vertical-align="bottom" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('preserveAspectRatio="xMinYMax meet"');
|
||||||
|
});
|
||||||
|
});
|
40
packages/vue2/tests/offline/10-basic.test.js
Normal file
40
packages/vue2/tests/offline/10-basic.test.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Creating component', () => {
|
||||||
|
test('with wrapper', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon='icon' />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
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>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('without wrapper', () => {
|
||||||
|
const wrapper = mount(Icon, {
|
||||||
|
propsData: {
|
||||||
|
icon: iconData,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
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>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
46
packages/vue2/tests/offline/10-empty.test.js
Normal file
46
packages/vue2/tests/offline/10-empty.test.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { Icon } from '../../dist/offline';
|
||||||
|
|
||||||
|
describe('Empty icon', () => {
|
||||||
|
test('basic test', () => {
|
||||||
|
const wrapper = mount(Icon, {
|
||||||
|
propsData: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with child node', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon><i class="fa fa-home" /></Icon>`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||||
|
'<i class="fa fa-home"></i>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with text child node', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon>icon</Icon>`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.text()).toEqual('icon');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with multiple childen', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon><i class="fa fa-home" /> Home icon</Icon>`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
|
||||||
|
'<span><i class="fa fa-home"></i> Home icon</span>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
144
packages/vue2/tests/offline/20-attributes.test.js
Normal file
144
packages/vue2/tests/offline/20-attributes.test.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Passing attributes', () => {
|
||||||
|
test('title', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" title="Icon!" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('role="img" title="Icon!"');
|
||||||
|
|
||||||
|
// Make sure aria-hidden exists (for tests below)
|
||||||
|
expect(html).toContain('aria-hidden="true"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('aria-hidden', () => {
|
||||||
|
// dashes, string value
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" aria-hidden="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('aria-hidden="true"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ariaHidden', () => {
|
||||||
|
// camelCase, boolean value
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :ariaHidden="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('aria-hidden="true"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('style as string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" style="color: red;" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: red;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('style as object', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :style="style" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
style: {
|
||||||
|
color: 'red',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: red;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('color', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" color="red" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: red;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('color with style', () => {
|
||||||
|
// In Vue 2 style overrides color in class components
|
||||||
|
// Can be fixed by using functional component, but functional component is not possible with API
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" color="purple" style="color: green;" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="color: green;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('attributes that cannot change', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" viewBox="0 0 0 0" preserveAspectRatio="none" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).not.toContain('viewBox="0 0 0 0"');
|
||||||
|
expect(html).not.toContain('preserveAspectRatio="none"');
|
||||||
|
});
|
||||||
|
});
|
68
packages/vue2/tests/offline/20-dimensions.test.js
Normal file
68
packages/vue2/tests/offline/20-dimensions.test.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Dimensions', () => {
|
||||||
|
test('height', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" height="48" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('height="48"');
|
||||||
|
expect(html).toContain('width="48"');
|
||||||
|
expect(html).not.toContain('height="1em"');
|
||||||
|
expect(html).not.toContain('width="1em"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('width and height', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :width="32" height="48" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('height="48"');
|
||||||
|
expect(html).toContain('width="32"');
|
||||||
|
expect(html).not.toContain('height="1em"');
|
||||||
|
expect(html).not.toContain('width="1em"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('auto', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" height="auto" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
const html = wrapper.html();
|
||||||
|
expect(html).toContain('height="24"');
|
||||||
|
expect(html).toContain('width="24"');
|
||||||
|
expect(html).not.toContain('height="1em"');
|
||||||
|
expect(html).not.toContain('width="1em"');
|
||||||
|
});
|
||||||
|
});
|
41
packages/vue2/tests/offline/20-ids.test.js
Normal file
41
packages/vue2/tests/offline/20-ids.test.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { Icon } from '../../dist/offline';
|
||||||
|
|
||||||
|
const iconDataWithID = {
|
||||||
|
body:
|
||||||
|
'<defs><path id="ssvg-id-1st-place-medala" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medald" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalf" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalh" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalj" d="M.93.01h120.55v58.36H.93z"/><path id="ssvg-id-1st-place-medalm" d="M.93.01h120.55v58.36H.93z"/><path d="M52.849 78.373v-3.908c3.681-.359 6.25-.958 7.703-1.798c1.454-.84 2.54-2.828 3.257-5.962h4.021v40.385h-5.437V78.373h-9.544z" id="ssvg-id-1st-place-medalp"/><linearGradient x1="49.998%" y1="-13.249%" x2="49.998%" y2="90.002%" id="ssvg-id-1st-place-medalb"><stop stop-color="#1E88E5" offset="13.55%"/><stop stop-color="#1565C0" offset="93.8%"/></linearGradient><linearGradient x1="26.648%" y1="2.735%" x2="77.654%" y2="105.978%" id="ssvg-id-1st-place-medalk"><stop stop-color="#64B5F6" offset="13.55%"/><stop stop-color="#2196F3" offset="94.62%"/></linearGradient><radialGradient cx="22.368%" cy="12.5%" fx="22.368%" fy="12.5%" r="95.496%" id="ssvg-id-1st-place-medalo"><stop stop-color="#FFEB3B" offset="29.72%"/><stop stop-color="#FBC02D" offset="95.44%"/></radialGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medalc" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medala"/></mask><path fill="url(#ssvg-id-1st-place-medalb)" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medalc)" d="M45.44 42.18h31.43l30-48.43H75.44z"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medale" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medald"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medale)" fill="#424242" fill-rule="nonzero"><path d="M101.23-3L75.2 39H50.85L77.11-3h24.12zm5.64-3H75.44l-30 48h31.42l30.01-48z"/></g></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medalg" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalf"/></mask><path d="M79 30H43c-4.42 0-8 3.58-8 8v16.04c0 2.17 1.8 3.95 4.02 3.96h.01c2.23-.01 4.97-1.75 4.97-3.96V44c0-1.1.9-2 2-2h30c1.1 0 2 .9 2 2v9.93c0 1.98 2.35 3.68 4.22 4.04c.26.05.52.08.78.08c2.21 0 4-1.79 4-4V38c0-4.42-3.58-8-8-8z" fill="#FDD835" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medalg)"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medali" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalh"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medali)" fill="#424242" fill-rule="nonzero"><path d="M79 32c3.31 0 6 2.69 6 6v16.04A2.006 2.006 0 0 1 82.59 56c-1.18-.23-2.59-1.35-2.59-2.07V44c0-2.21-1.79-4-4-4H46c-2.21 0-4 1.79-4 4v10.04c0 .88-1.64 1.96-2.97 1.96c-1.12-.01-2.03-.89-2.03-1.96V38c0-3.31 2.69-6 6-6h36zm0-2H43c-4.42 0-8 3.58-8 8v16.04c0 2.17 1.8 3.95 4.02 3.96h.01c2.23-.01 4.97-1.75 4.97-3.96V44c0-1.1.9-2 2-2h30c1.1 0 2 .9 2 2v9.93c0 1.98 2.35 3.68 4.22 4.04c.26.05.52.08.78.08c2.21 0 4-1.79 4-4V38c0-4.42-3.58-8-8-8z"/></g></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medall" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalj"/></mask><path fill="url(#ssvg-id-1st-place-medalk)" fill-rule="nonzero" mask="url(#ssvg-id-1st-place-medall)" d="M76.87 42.18H45.44l-30-48.43h31.43z"/></g><g transform="translate(3 4)"><mask id="ssvg-id-1st-place-medaln" fill="#fff"><use xlink:href="#ssvg-id-1st-place-medalm"/></mask><g opacity=".2" mask="url(#ssvg-id-1st-place-medaln)" fill="#424242" fill-rule="nonzero"><path d="M45.1-3l26.35 42H47.1L20.86-3H45.1zm1.77-3H15.44l30 48h31.42L46.87-6z"/></g></g><circle fill="url(#ssvg-id-1st-place-medalo)" fill-rule="nonzero" cx="64" cy="86" r="38"/><path d="M64 51c19.3 0 35 15.7 35 35s-15.7 35-35 35s-35-15.7-35-35s15.7-35 35-35zm0-3c-20.99 0-38 17.01-38 38s17.01 38 38 38s38-17.01 38-38s-17.01-38-38-38z" opacity=".2" fill="#424242" fill-rule="nonzero"/><path d="M47.3 63.59h33.4v44.4H47.3z"/><use fill="#000" xlink:href="#ssvg-id-1st-place-medalp"/><use fill="#FFA000" xlink:href="#ssvg-id-1st-place-medalp"/></g>',
|
||||||
|
width: 128,
|
||||||
|
height: 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Replacing IDs', () => {
|
||||||
|
test('default behavior', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconDataWithID,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('ssvg-id-1st-place-medala');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('custom generator', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" id="test" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconDataWithID,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('id="test-0"');
|
||||||
|
});
|
||||||
|
});
|
135
packages/vue2/tests/offline/20-inline.test.js
Normal file
135
packages/vue2/tests/offline/20-inline.test.js
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Inline attribute', () => {
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" inline="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('false string', () => {
|
||||||
|
// "false" = true
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" inline="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('true', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('style="vertical-align: -0.125em;"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('false', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain(
|
||||||
|
'style="vertical-align: -0.125em;"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('inline and style string', () => {
|
||||||
|
// Style goes after vertical-align
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" style="color: red;" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'vertical-align: -0.125em; color: red;'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('inline and style object', () => {
|
||||||
|
// Style goes after vertical-align
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" :style="style" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
style: {
|
||||||
|
color: 'red',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'vertical-align: -0.125em; color: red;'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('inline and style overriding it', () => {
|
||||||
|
// Style goes after vertical-align
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :inline="true" :style="style" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
style: {
|
||||||
|
verticalAlign: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
// For some reason style is duplicated
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'style="vertical-align: 0; vertical-align: 0;"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
100
packages/vue2/tests/offline/20-storage.test.js
Normal file
100
packages/vue2/tests/offline/20-storage.test.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { Icon, addIcon, addCollection } from '../../dist/offline';
|
||||||
|
|
||||||
|
const iconData = {
|
||||||
|
body:
|
||||||
|
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Using storage', () => {
|
||||||
|
test('using storage', () => {
|
||||||
|
addIcon('test-icon', iconData);
|
||||||
|
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon icon="test-icon" />`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
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>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('using storage with icon set', () => {
|
||||||
|
const iconSet = {
|
||||||
|
prefix: 'mdi-light',
|
||||||
|
icons: {
|
||||||
|
account: {
|
||||||
|
body:
|
||||||
|
'<path d="M11.5 14c4.142 0 7.5 1.567 7.5 3.5V20H4v-2.5c0-1.933 3.358-3.5 7.5-3.5zm6.5 3.5c0-1.38-2.91-2.5-6.5-2.5S5 16.12 5 17.5V19h13v-1.5zM11.5 5a3.5 3.5 0 1 1 0 7a3.5 3.5 0 0 1 0-7zm0 1a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
home: {
|
||||||
|
body:
|
||||||
|
'<path d="M16 8.414l-4.5-4.5L4.414 11H6v8h3v-6h5v6h3v-8h1.586L17 9.414V6h-1v2.414zM2 12l9.5-9.5L15 6V5h3v4l3 3h-3v7.998h-5v-6h-3v6H5V12H2z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
addCollection(iconSet);
|
||||||
|
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: 'mdi-light:account',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
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="M11.5 14c4.142 0 7.5 1.567 7.5 3.5V20H4v-2.5c0-1.933 3.358-3.5 7.5-3.5zm6.5 3.5c0-1.38-2.91-2.5-6.5-2.5S5 16.12 5 17.5V19h13v-1.5zM11.5 5a3.5 3.5 0 1 1 0 7a3.5 3.5 0 0 1 0-7zm0 1a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5z" fill="currentColor"></path></svg>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('using storage with icon set with custom prefix', () => {
|
||||||
|
const iconSet = {
|
||||||
|
prefix: 'mdi-light',
|
||||||
|
icons: {
|
||||||
|
'account-alert': {
|
||||||
|
body:
|
||||||
|
'<path d="M10.5 14c4.142 0 7.5 1.567 7.5 3.5V20H3v-2.5c0-1.933 3.358-3.5 7.5-3.5zm6.5 3.5c0-1.38-2.91-2.5-6.5-2.5S4 16.12 4 17.5V19h13v-1.5zM10.5 5a3.5 3.5 0 1 1 0 7a3.5 3.5 0 0 1 0-7zm0 1a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5zM20 16v-1h1v1h-1zm0-3V7h1v6h-1z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
'link': {
|
||||||
|
body:
|
||||||
|
'<path d="M8 13v-1h7v1H8zm7.5-6a5.5 5.5 0 1 1 0 11H13v-1h2.5a4.5 4.5 0 1 0 0-9H13V7h2.5zm-8 11a5.5 5.5 0 1 1 0-11H10v1H7.5a4.5 4.5 0 1 0 0 9H10v1H7.5z" fill="currentColor"/>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
addCollection(iconSet, 'custom-');
|
||||||
|
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon icon="custom-link" />`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
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="M8 13v-1h7v1H8zm7.5-6a5.5 5.5 0 1 1 0 11H13v-1h2.5a4.5 4.5 0 1 0 0-9H13V7h2.5zm-8 11a5.5 5.5 0 1 1 0-11H10v1H7.5a4.5 4.5 0 1 0 0 9H10v1H7.5z" fill="currentColor"></path></svg>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('missing icon from storage', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon icon="missing-icon" />`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual('');
|
||||||
|
});
|
||||||
|
});
|
208
packages/vue2/tests/offline/20-transformations.test.js
Normal file
208
packages/vue2/tests/offline/20-transformations.test.js
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
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"/>',
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Rotation', () => {
|
||||||
|
test('number', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :rotate="1" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
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"><g transform="rotate(90 12 12)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" rotate="180deg" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('<g transform="rotate(180 12 12)">');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Flip', () => {
|
||||||
|
test('boolean', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :hFlip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(24 0) scale(-1 1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="vertical" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(0 24) scale(1 -1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string and boolean', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="horizontal" :vFlip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('<g transform="rotate(180 12 12)">');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string for boolean attribute', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" horizontal-flip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(24 0) scale(-1 1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('shorthand and boolean', () => {
|
||||||
|
// 'flip' is processed after 'hFlip', overwriting value
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="horizontal" :hFlip="false" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'<g transform="translate(24 0) scale(-1 1)">'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('shorthand and boolean as string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" flip="vertical" :horizontal-flip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('<g transform="rotate(180 12 12)">');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('wrong case', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" :vflip="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).not.toContain('<g transform="');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Alignment and slice', () => {
|
||||||
|
test('vAlign and slice', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" vAlign="top" :slice="true" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain(
|
||||||
|
'preserveAspectRatio="xMidYMin slice"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" align="left bottom" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('preserveAspectRatio="xMinYMax meet"');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('aliases', () => {
|
||||||
|
const Wrapper = {
|
||||||
|
components: { Icon },
|
||||||
|
template: `<Icon :icon="icon" h-align="left" vertical-align="bottom" />`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icon: iconData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(Wrapper, {});
|
||||||
|
expect(wrapper.html()).toContain('preserveAspectRatio="xMinYMax meet"');
|
||||||
|
});
|
||||||
|
});
|
@ -2,7 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"target": "ES2019",
|
"target": "ESNext",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
|
Loading…
Reference in New Issue
Block a user