mirror of
https://github.com/iconify/iconify.git
synced 2025-01-05 15:02:09 +00:00
feat(tailwind): new version with dynamic icons
BREAKING CHANGE: plugin uses named exports now, see README.md for usage
This commit is contained in:
parent
c052341bc2
commit
2841b3ff05
@ -7,22 +7,23 @@ This plugin creates CSS for over 100k open source icons.
|
||||
## Usage
|
||||
|
||||
1. Install packages icon sets.
|
||||
2. In `tailwind.config.js` import plugin and specify list of icons you want to load.
|
||||
2. In `tailwind.config.js` import `addDynamicIconSelectors` from `@iconify/tailwind`.
|
||||
|
||||
## HTML
|
||||
|
||||
To use icon in HTML, it is as easy as adding 2 class names:
|
||||
|
||||
- Class name for icon set: `icon--{prefix}`.
|
||||
- Class name for icon: `icon--{prefix}--{name}`.
|
||||
To use icon in HTML, add class with class name like this: `icon-[mdi-light--home]`
|
||||
|
||||
```html
|
||||
<span class="icon--mdi icon--mdi--home"></span>
|
||||
<span class="icon-[mdi-light--home]"></span>
|
||||
```
|
||||
|
||||
Why 2 class names? It reduces duplication and makes it easy to target all icons from one icon set.
|
||||
Class name has 3 parts:
|
||||
|
||||
You can change that with options: you can change class names format, you can disable common selector. See [options for function used by plugin](https://docs.iconify.design/tools/utils/get-icons-css.html).
|
||||
- Selectot prefix, which can be set in `prefix` option of plugin. Default value is `icon`.
|
||||
- `-` to tell Tailwind that class name is not complete.
|
||||
- `[{prefix}--{name}]` for icon name, where `{prefix}` is icon set prefix, `{name}` is icon name.
|
||||
|
||||
In Iconify all icon names use the following format: `{prefix}:{name}`. Due to limitations of Tailwind CSS, same format cannot be used with plugin, so instead, prefix and name are separated by double dash: `{prefix}--{name}`.
|
||||
|
||||
### Color, size, alignment
|
||||
|
||||
@ -35,7 +36,7 @@ Icon color cannot be changed for icons with hardcoded palette, such as most emoj
|
||||
To align icon below baseline, add negative vertical alignment, like this (you can also use Tailwind class for that):
|
||||
|
||||
```html
|
||||
<span class="icon--mdi icon--mdi--home" style="vertical-align: -0.125em"></span>
|
||||
<span class="icon-[mdi--home]" style="vertical-align: -0.125em"></span>
|
||||
```
|
||||
|
||||
## Installing icon sets
|
||||
@ -55,10 +56,10 @@ See [Iconify documentation](https://docs.iconify.design/icons/json.html) for lis
|
||||
Add this to `tailwind.config.js`:
|
||||
|
||||
```js
|
||||
const iconifyPlugin = require('@iconify/tailwind');
|
||||
const { addDynamicIconSelectors } = require('@iconify/tailwind');
|
||||
```
|
||||
|
||||
Then in plugins section add `iconifyPlugin` with list of icons you want to load.
|
||||
Then in plugins section add `addDynamicIconSelectors`.
|
||||
|
||||
Example:
|
||||
|
||||
@ -69,22 +70,45 @@ module.exports = {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
// Iconify plugin with list of icons you need
|
||||
iconifyPlugin(['mdi:home', 'mdi-light:account']),
|
||||
// Iconify plugin
|
||||
addDynamicIconSelectors(),
|
||||
],
|
||||
presets: [],
|
||||
};
|
||||
```
|
||||
|
||||
### Icon names
|
||||
|
||||
Unfortunately Tailwind CSS cannot dynamically find all icon names. You need to specify list of icons you want to use.
|
||||
|
||||
### Options
|
||||
|
||||
Plugin accepts options as a second parameter. You can use it to change selectors.
|
||||
Plugin accepts options as a second parameter:
|
||||
|
||||
See [documentation for function used by plugin](https://docs.iconify.design/tools/utils/get-icons-css.html) for list of options.
|
||||
- `prefix` is class name prefix. Default value is `icon`. Make sure there is no `-` at the end: it is added in classes, but not in plugin parameter.
|
||||
- `overrideOnly`: set to `true` to generate rules that override only icon data. See below.
|
||||
- `files`: list of custom files for icon sets. Key is icon set prefix, value is location of `.json` file with icon set in IconifyJSON format.
|
||||
- `iconSet`: list of custom icon sets. Key is prefix, value is either icon set data in `IconifyJSON` format or a synchronous callback that returns `IconifyJSON` data.
|
||||
|
||||
#### overrideOnly
|
||||
|
||||
You can use `overrideOnly` to load some icons without full rules, such as changing icon on hover when main and hover icons are from the same icon set and have same width/height ratio.
|
||||
|
||||
Example of config:
|
||||
|
||||
```js
|
||||
plugins: [
|
||||
// `icon-`
|
||||
addDynamicIconSelectors(),
|
||||
// `icon-hover-`
|
||||
addDynamicIconSelectors({
|
||||
prefix: "icon-hover",
|
||||
overrideOnly: true,
|
||||
}),
|
||||
],
|
||||
```
|
||||
|
||||
and usage in HTML:
|
||||
|
||||
```html
|
||||
<span class="icon-[mdi--arrow-left] hover:icon-hover-[mdi--arrow-right]"></span>
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/tailwind",
|
||||
"description": "Iconify plugin for Tailwind CSS",
|
||||
"author": "Vjacheslav Trushkin <cyberalien@gmail.com> (https://iconify.design)",
|
||||
"version": "0.0.2",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/plugin.js",
|
||||
"types": "./dist/plugin.d.ts",
|
||||
|
43
plugins/tailwind/src/clean.ts
Normal file
43
plugins/tailwind/src/clean.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { getIconsCSSData } from '@iconify/utils/lib/css/icons';
|
||||
import { loadIconSet } from './loader';
|
||||
import { getIconNames } from './names';
|
||||
import type { CleanIconifyPluginOptions } from './options';
|
||||
|
||||
/**
|
||||
* Get CSS rules for icons list
|
||||
*/
|
||||
export function getCSSRulesForIcons(
|
||||
icons: string[] | string,
|
||||
options: CleanIconifyPluginOptions = {}
|
||||
): Record<string, Record<string, string>> {
|
||||
const rules = Object.create(null) as Record<string, Record<string, string>>;
|
||||
|
||||
// Get all icons
|
||||
const prefixes = getIconNames(icons);
|
||||
|
||||
// Parse all icon sets
|
||||
for (const prefix in prefixes) {
|
||||
const iconSet = loadIconSet(prefix, options);
|
||||
if (!iconSet) {
|
||||
throw new Error(`Cannot load icon set for "${prefix}"`);
|
||||
}
|
||||
const generated = getIconsCSSData(
|
||||
iconSet,
|
||||
Array.from(prefixes[prefix]),
|
||||
options
|
||||
);
|
||||
|
||||
const result = generated.common
|
||||
? [generated.common, ...generated.css]
|
||||
: generated.css;
|
||||
result.forEach((item) => {
|
||||
const selector =
|
||||
item.selector instanceof Array
|
||||
? item.selector.join(', ')
|
||||
: item.selector;
|
||||
rules[selector] = item.rules;
|
||||
});
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
44
plugins/tailwind/src/dynamic.ts
Normal file
44
plugins/tailwind/src/dynamic.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { getIconsCSSData } from '@iconify/utils/lib/css/icons';
|
||||
import { matchIconName } from '@iconify/utils/lib/icon/name';
|
||||
import { loadIconSet } from './loader';
|
||||
import type { DynamicIconifyPluginOptions } from './options';
|
||||
|
||||
/**
|
||||
* Get dynamic CSS rules
|
||||
*/
|
||||
export function getDynamicCSSRules(
|
||||
icon: string,
|
||||
options: DynamicIconifyPluginOptions = {}
|
||||
): Record<string, string> {
|
||||
const nameParts = icon.split(/--|\:/);
|
||||
if (nameParts.length !== 2) {
|
||||
throw new Error(`Invalid icon name: "${icon}"`);
|
||||
}
|
||||
|
||||
const [prefix, name] = nameParts;
|
||||
if (!prefix.match(matchIconName) || !name.match(matchIconName)) {
|
||||
throw new Error(`Invalid icon name: "${icon}"`);
|
||||
}
|
||||
|
||||
const iconSet = loadIconSet(prefix, options);
|
||||
if (!iconSet) {
|
||||
throw new Error(`Cannot load icon set for "${prefix}"`);
|
||||
}
|
||||
|
||||
const generated = getIconsCSSData(iconSet, [name], {
|
||||
iconSelector: '.icon',
|
||||
});
|
||||
if (generated.css.length !== 1) {
|
||||
throw new Error(`Something went wrong generating "${icon}"`);
|
||||
}
|
||||
|
||||
return {
|
||||
// Common rules
|
||||
...(options.overrideOnly || !generated.common?.rules
|
||||
? {}
|
||||
: generated.common.rules),
|
||||
|
||||
// Icon rules
|
||||
...generated.css[0].rules,
|
||||
};
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
import { getIconsCSSData } from '@iconify/utils/lib/css/icons';
|
||||
import { matchIconName } from '@iconify/utils/lib/icon/name';
|
||||
import { loadIconSet } from './loader';
|
||||
import type { IconifyPluginOptions } from './options';
|
||||
|
||||
const missingIconsListError =
|
||||
'TailwindCSS cannot dynamically find all used icons. Need to pass list of used icons to Iconify plugin.';
|
||||
|
||||
/**
|
||||
* Get icon names from list
|
||||
*/
|
||||
function getIconNames(icons: string[] | string): Record<string, Set<string>> {
|
||||
const prefixes = Object.create(null) as Record<string, Set<string>>;
|
||||
|
||||
// Add entry
|
||||
const add = (prefix: string, name: string) => {
|
||||
if (
|
||||
typeof prefix === 'string' &&
|
||||
prefix.match(matchIconName) &&
|
||||
typeof name === 'string' &&
|
||||
name.match(matchIconName)
|
||||
) {
|
||||
(prefixes[prefix] || (prefixes[prefix] = new Set())).add(name);
|
||||
}
|
||||
};
|
||||
|
||||
// Comma or space separated string
|
||||
let iconNames: string[] | undefined;
|
||||
if (typeof icons === 'string') {
|
||||
iconNames = icons.split(/[\s,.]/);
|
||||
} else if (icons instanceof Array) {
|
||||
iconNames = [];
|
||||
// Split each array entry
|
||||
icons.forEach((item) => {
|
||||
item.split(/[\s,.]/).forEach((name) => iconNames.push(name));
|
||||
});
|
||||
} else {
|
||||
throw new Error(missingIconsListError);
|
||||
}
|
||||
|
||||
// Parse array
|
||||
if (iconNames?.length) {
|
||||
iconNames.forEach((icon) => {
|
||||
if (!icon.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt prefix:name split
|
||||
const nameParts = icon.split(':');
|
||||
if (nameParts.length === 2) {
|
||||
add(nameParts[0], nameParts[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt icon class: .icon--{prefix}--{name}
|
||||
// with or without dot
|
||||
const classParts = icon.split('--');
|
||||
if (classParts[0].match(/^\.?icon$/)) {
|
||||
if (classParts.length === 3) {
|
||||
add(classParts[1], classParts[2]);
|
||||
return;
|
||||
}
|
||||
if (classParts.length === 2) {
|
||||
// Partial match
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Throw error
|
||||
throw new Error(`Cannot resolve icon: "${icon}"`);
|
||||
});
|
||||
} else {
|
||||
throw new Error(missingIconsListError);
|
||||
}
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CSS rules for icon
|
||||
*/
|
||||
export function getCSSRules(
|
||||
icons: string[] | string,
|
||||
options: IconifyPluginOptions = {}
|
||||
): Record<string, Record<string, string>> {
|
||||
const rules = Object.create(null) as Record<string, Record<string, string>>;
|
||||
|
||||
// Get all icons
|
||||
const prefixes = getIconNames(icons);
|
||||
|
||||
// Parse all icon sets
|
||||
for (const prefix in prefixes) {
|
||||
const iconSet = loadIconSet(prefix, options);
|
||||
if (!iconSet) {
|
||||
throw new Error(`Cannot load icon set for "${prefix}"`);
|
||||
}
|
||||
const generated = getIconsCSSData(
|
||||
iconSet,
|
||||
Array.from(prefixes[prefix]),
|
||||
options
|
||||
);
|
||||
|
||||
const result = generated.common
|
||||
? [generated.common, ...generated.css]
|
||||
: generated.css;
|
||||
result.forEach((item) => {
|
||||
const selector =
|
||||
item.selector instanceof Array
|
||||
? item.selector.join(', ')
|
||||
: item.selector;
|
||||
rules[selector] = item.rules;
|
||||
});
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dynamic CSS rule
|
||||
*/
|
||||
export function getDynamicCSSRules(
|
||||
selector: string,
|
||||
icon: string,
|
||||
options: IconifyPluginOptions = {}
|
||||
): Record<string, string> {
|
||||
const nameParts = icon.split('--');
|
||||
let nameError = `Invalid icon name: "${icon}"`;
|
||||
if (nameParts.length !== 2) {
|
||||
if (nameParts.length === 1 && icon.indexOf(':') !== -1) {
|
||||
nameError += `. "{prefix}:{name}" is not supported because of Tailwind limitations, use "{prefix}--{name}" (use double dash!) instead.`;
|
||||
}
|
||||
throw new Error(nameError);
|
||||
}
|
||||
|
||||
const [prefix, name] = nameParts;
|
||||
if (!prefix.match(matchIconName) || !name.match(matchIconName)) {
|
||||
throw new Error(nameError);
|
||||
}
|
||||
|
||||
const iconSet = loadIconSet(prefix, options);
|
||||
if (!iconSet) {
|
||||
throw new Error(`Cannot load icon set for "${prefix}"`);
|
||||
}
|
||||
|
||||
const generated = getIconsCSSData(iconSet, [name], {
|
||||
...options,
|
||||
// One selector
|
||||
iconSelector: selector,
|
||||
commonSelector: selector,
|
||||
overrideSelector: selector,
|
||||
});
|
||||
if (generated.css.length !== 1) {
|
||||
throw new Error(`Something went wrong generating "${icon}"`);
|
||||
}
|
||||
return {
|
||||
...(generated.common?.rules || {}),
|
||||
...generated.css[0].rules,
|
||||
};
|
||||
}
|
73
plugins/tailwind/src/names.ts
Normal file
73
plugins/tailwind/src/names.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { matchIconName } from '@iconify/utils/lib/icon/name';
|
||||
|
||||
/**
|
||||
* Get icon names from list
|
||||
*/
|
||||
export function getIconNames(
|
||||
icons: string[] | string
|
||||
): Record<string, Set<string>> | undefined {
|
||||
const prefixes = Object.create(null) as Record<string, Set<string>>;
|
||||
|
||||
// Add entry
|
||||
const add = (prefix: string, name: string) => {
|
||||
if (
|
||||
typeof prefix === 'string' &&
|
||||
prefix.match(matchIconName) &&
|
||||
typeof name === 'string' &&
|
||||
name.match(matchIconName)
|
||||
) {
|
||||
(prefixes[prefix] || (prefixes[prefix] = new Set())).add(name);
|
||||
}
|
||||
};
|
||||
|
||||
// Comma or space separated string
|
||||
let iconNames: string[] | undefined;
|
||||
if (typeof icons === 'string') {
|
||||
iconNames = icons.split(/[\s,.]/);
|
||||
} else if (icons instanceof Array) {
|
||||
iconNames = [];
|
||||
// Split each array entry
|
||||
icons.forEach((item) => {
|
||||
item.split(/[\s,.]/).forEach((name) => iconNames.push(name));
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse array
|
||||
if (iconNames?.length) {
|
||||
iconNames.forEach((icon) => {
|
||||
if (!icon.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt prefix:name split
|
||||
const nameParts = icon.split(':');
|
||||
if (nameParts.length === 2) {
|
||||
add(nameParts[0], nameParts[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt icon class: .icon--{prefix}--{name}
|
||||
// with or without dot
|
||||
const classParts = icon.split('--');
|
||||
if (classParts[0].match(/^\.?icon$/)) {
|
||||
if (classParts.length === 3) {
|
||||
add(classParts[1], classParts[2]);
|
||||
return;
|
||||
}
|
||||
if (classParts.length === 2) {
|
||||
// Partial match
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Throw error
|
||||
throw new Error(`Cannot resolve icon: "${icon}"`);
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
return prefixes;
|
||||
}
|
@ -1,29 +1,30 @@
|
||||
import type { IconCSSIconSetOptions } from '@iconify/utils/lib/css/types';
|
||||
import type { IconifyPluginLoaderOptions } from './loader';
|
||||
|
||||
/**
|
||||
* Options for locating icon sets
|
||||
* Common options
|
||||
*/
|
||||
export interface IconifyPluginFileOptions {
|
||||
// Files
|
||||
files?: Record<string, string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for matching dynamic icon names
|
||||
*/
|
||||
export interface IconifyPluginDynamicPrefixOptions {
|
||||
// Dynamic prefix for selectors. Default is `icon`
|
||||
// Allows using icon names like `<span class="icon[mdi--home]"></span>
|
||||
// Where prefix and name are separated by '--' because Tailwind does not allow ':'
|
||||
dynamicPrefix?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* All options
|
||||
*/
|
||||
export interface IconifyPluginOptions
|
||||
extends IconCSSIconSetOptions,
|
||||
IconifyPluginDynamicPrefixOptions,
|
||||
IconifyPluginFileOptions {
|
||||
export interface CommonIconifyPluginOptions extends IconifyPluginLoaderOptions {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for clean class names
|
||||
*/
|
||||
export interface CleanIconifyPluginOptions
|
||||
extends CommonIconifyPluginOptions,
|
||||
IconCSSIconSetOptions {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for dynamic class names
|
||||
*/
|
||||
export interface DynamicIconifyPluginOptions
|
||||
extends CommonIconifyPluginOptions {
|
||||
// Class prefix
|
||||
prefix?: string;
|
||||
|
||||
// Inclue icon-specific selectors only
|
||||
overrideOnly?: true;
|
||||
}
|
||||
|
@ -1,13 +1,29 @@
|
||||
import plugin from 'tailwindcss/plugin';
|
||||
import { getCSSRules, getDynamicCSSRules } from './iconify';
|
||||
import type { IconifyPluginOptions } from './options';
|
||||
import { getCSSRulesForIcons } from './clean';
|
||||
import { getDynamicCSSRules } from './dynamic';
|
||||
import type {
|
||||
CleanIconifyPluginOptions,
|
||||
DynamicIconifyPluginOptions,
|
||||
} from './options';
|
||||
|
||||
/**
|
||||
* Iconify plugin
|
||||
* Generate styles for dynamic selector: class="icon-[mdi-light--home]"
|
||||
*/
|
||||
function iconifyPlugin(
|
||||
export function addDynamicIconSelectors(options?: DynamicIconifyPluginOptions) {
|
||||
const prefix = options?.prefix || 'icon';
|
||||
return plugin(({ matchComponents }) => {
|
||||
matchComponents({
|
||||
[prefix]: (icon: string) => getDynamicCSSRules(icon, options),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate styles for preset list of icons
|
||||
*/
|
||||
export function addCleanIconSelectors(
|
||||
icons?: string[] | string,
|
||||
options?: IconifyPluginOptions
|
||||
options?: CleanIconifyPluginOptions
|
||||
) {
|
||||
const passedOptions =
|
||||
typeof icons === 'object' && !(icons instanceof Array)
|
||||
@ -16,32 +32,17 @@ function iconifyPlugin(
|
||||
const passedIcons =
|
||||
typeof icons !== 'object' || icons instanceof Array ? icons : void 0;
|
||||
|
||||
// Get selector for dynamic classes
|
||||
const dynamicSelector = passedOptions.dynamicPrefix || 'icon';
|
||||
|
||||
// Get hardcoded list of icons
|
||||
const rules = passedIcons
|
||||
? getCSSRules(passedIcons, passedOptions)
|
||||
? getCSSRulesForIcons(passedIcons, passedOptions)
|
||||
: void 0;
|
||||
|
||||
return plugin(({ addUtilities, matchComponents }) => {
|
||||
if (rules) {
|
||||
addUtilities(rules);
|
||||
}
|
||||
matchComponents({
|
||||
[dynamicSelector]: (icon: string) =>
|
||||
getDynamicCSSRules(
|
||||
`.${dynamicSelector}-[${icon}]`,
|
||||
icon,
|
||||
passedOptions
|
||||
),
|
||||
});
|
||||
addUtilities(rules);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Export stuff
|
||||
* Export types
|
||||
*/
|
||||
export default iconifyPlugin;
|
||||
|
||||
export type { IconifyPluginOptions };
|
||||
export type { CleanIconifyPluginOptions, DynamicIconifyPluginOptions };
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { getCSSRules } from '../src/iconify';
|
||||
import { getCSSRulesForIcons } from '../src/clean';
|
||||
|
||||
describe('Testing CSS rules', () => {
|
||||
describe('Testing clean CSS rules', () => {
|
||||
it('One icon', () => {
|
||||
const data = getCSSRules('mdi-light:home');
|
||||
const data = getCSSRulesForIcons('mdi-light:home');
|
||||
expect(Object.keys(data)).toEqual([
|
||||
'.icon--mdi-light',
|
||||
'.icon--mdi-light--home',
|
||||
@ -11,7 +11,7 @@ describe('Testing CSS rules', () => {
|
||||
});
|
||||
|
||||
it('Multiple icons from same icon set', () => {
|
||||
const data = getCSSRules([
|
||||
const data = getCSSRulesForIcons([
|
||||
// By name
|
||||
'mdi-light:home',
|
||||
// By selector
|
||||
@ -32,7 +32,7 @@ describe('Testing CSS rules', () => {
|
||||
});
|
||||
|
||||
it('Multiple icon sets', () => {
|
||||
const data = getCSSRules([
|
||||
const data = getCSSRulesForIcons([
|
||||
// MDI Light
|
||||
'mdi-light:home',
|
||||
// Line MD
|
||||
@ -49,7 +49,7 @@ describe('Testing CSS rules', () => {
|
||||
it('Bad class name', () => {
|
||||
let threw = false;
|
||||
try {
|
||||
getCSSRules(['icon--mdi-light--home test']);
|
||||
getCSSRulesForIcons(['icon--mdi-light--home test']);
|
||||
} catch {
|
||||
threw = true;
|
||||
}
|
||||
@ -59,7 +59,7 @@ describe('Testing CSS rules', () => {
|
||||
it('Bad icon set', () => {
|
||||
let threw = false;
|
||||
try {
|
||||
getCSSRules('test123:home');
|
||||
getCSSRulesForIcons('test123:home');
|
||||
} catch {
|
||||
threw = true;
|
||||
}
|
59
plugins/tailwind/tests/dynamic-css-test.ts
Normal file
59
plugins/tailwind/tests/dynamic-css-test.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { getDynamicCSSRules } from '../src/dynamic';
|
||||
|
||||
describe('Testing dynamic CSS rules', () => {
|
||||
it('One icon', () => {
|
||||
const data = getDynamicCSSRules('mdi-light--home');
|
||||
expect(typeof data['--svg']).toBe('string');
|
||||
expect(data).toEqual({
|
||||
'display': 'inline-block',
|
||||
'width': '1em',
|
||||
'height': '1em',
|
||||
'background-color': 'currentColor',
|
||||
'-webkit-mask': 'no-repeat center / 100%',
|
||||
'mask': 'no-repeat center / 100%',
|
||||
'-webkit-mask-image': 'var(--svg)',
|
||||
'mask-image': 'var(--svg)',
|
||||
'--svg': data['--svg'],
|
||||
});
|
||||
});
|
||||
|
||||
it('Only selectors that override icon', () => {
|
||||
const data = getDynamicCSSRules('mdi-light--home', {
|
||||
overrideOnly: true,
|
||||
});
|
||||
expect(typeof data['--svg']).toBe('string');
|
||||
expect(data).toEqual({
|
||||
'--svg': data['--svg'],
|
||||
});
|
||||
});
|
||||
|
||||
it('Missing icon', () => {
|
||||
let threw = false;
|
||||
try {
|
||||
getDynamicCSSRules('mdi-light--missing-icon-name');
|
||||
} catch {
|
||||
threw = true;
|
||||
}
|
||||
expect(threw).toBe(true);
|
||||
});
|
||||
|
||||
it('Bad icon name', () => {
|
||||
let threw = false;
|
||||
try {
|
||||
getDynamicCSSRules('mdi-home');
|
||||
} catch {
|
||||
threw = true;
|
||||
}
|
||||
expect(threw).toBe(true);
|
||||
});
|
||||
|
||||
it('Bad icon set', () => {
|
||||
let threw = false;
|
||||
try {
|
||||
getDynamicCSSRules('test123:home');
|
||||
} catch {
|
||||
threw = true;
|
||||
}
|
||||
expect(threw).toBe(true);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user