2
0
mirror of https://github.com/iconify/iconify.git synced 2024-09-29 13:39:08 +00:00

feat(tailwind): dynamic icon selectors

This commit is contained in:
Vjacheslav Trushkin 2023-01-11 23:42:32 +02:00
parent 2049c1d512
commit 53f4d2a4be
3 changed files with 85 additions and 6 deletions

View File

@ -148,3 +148,47 @@ export function getCSSRules(
return 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}"`);
}
console.log('Selector:', selector);
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,
};
}

View File

@ -8,11 +8,22 @@ export interface IconifyPluginFileOptions {
files?: Record<string, string>; 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 * All options
*/ */
export interface IconifyPluginOptions export interface IconifyPluginOptions
extends IconCSSIconSetOptions, extends IconCSSIconSetOptions,
IconifyPluginDynamicPrefixOptions,
IconifyPluginFileOptions { IconifyPluginFileOptions {
// //
} }

View File

@ -1,17 +1,41 @@
import plugin from 'tailwindcss/plugin'; import plugin from 'tailwindcss/plugin';
import { getCSSRules } from './iconify'; import { getCSSRules, getDynamicCSSRules } from './iconify';
import type { IconifyPluginOptions } from './options'; import type { IconifyPluginOptions } from './options';
/** /**
* Iconify plugin * Iconify plugin
*/ */
function iconifyPlugin( function iconifyPlugin(
icons: string[] | string, icons?: string[] | string,
options: IconifyPluginOptions = {} options?: IconifyPluginOptions
) { ) {
const rules = getCSSRules(icons, options); const passedOptions =
return plugin(({ addUtilities }) => { typeof icons === 'object' && !(icons instanceof Array)
? icons
: options || {};
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)
: void 0;
return plugin(({ addUtilities, matchComponents }) => {
if (rules) {
addUtilities(rules); addUtilities(rules);
}
matchComponents({
[dynamicSelector]: (icon: string) =>
getDynamicCSSRules(
`.${dynamicSelector}-[${icon}]`,
icon,
passedOptions
),
});
}); });
} }