@iconify/tailwind
Advanced tools
Comparing version 0.0.2 to 0.1.0
import { Config } from 'tailwindcss/types/config'; | ||
import type { IconifyJSON } from '@iconify/types'; | ||
import { PluginCreator } from 'tailwindcss/types/config'; | ||
/** | ||
* Generate styles for preset list of icons | ||
*/ | ||
export declare function addCleanIconSelectors(icons?: string[] | string, options?: CleanIconifyPluginOptions): { | ||
handler: PluginCreator; | ||
config?: Partial<Config>; | ||
}; | ||
/** | ||
* Generate styles for dynamic selector: class="icon-[mdi-light--home]" | ||
*/ | ||
export declare function addDynamicIconSelectors(options?: DynamicIconifyPluginOptions): { | ||
handler: PluginCreator; | ||
config?: Partial<Config>; | ||
}; | ||
/** | ||
* Options for clean class names | ||
*/ | ||
export declare interface CleanIconifyPluginOptions extends CommonIconifyPluginOptions, IconCSSIconSetOptions { | ||
} | ||
/** | ||
* Common options | ||
*/ | ||
declare interface CommonIconifyPluginOptions extends IconifyPluginLoaderOptions { | ||
} | ||
/** | ||
* Formatting modes. Same as in SASS | ||
@@ -10,2 +39,10 @@ */ | ||
/** | ||
* Options for dynamic class names | ||
*/ | ||
export declare interface DynamicIconifyPluginOptions extends CommonIconifyPluginOptions { | ||
prefix?: string; | ||
overrideOnly?: true; | ||
} | ||
/** | ||
* Formatting options | ||
@@ -61,23 +98,14 @@ */ | ||
/** | ||
* Iconify plugin | ||
* Callback for loading icon set | ||
*/ | ||
declare function iconifyPlugin(icons: string[] | string, options?: IconifyPluginOptions): { | ||
handler: PluginCreator; | ||
config?: Partial<Config>; | ||
}; | ||
export default iconifyPlugin; | ||
declare type IconifyJSONLoaderCallback = () => IconifyJSON; | ||
/** | ||
* Options for locating icon sets | ||
* Options for icon set loaders | ||
*/ | ||
declare interface IconifyPluginFileOptions { | ||
declare interface IconifyPluginLoaderOptions { | ||
files?: Record<string, string>; | ||
iconSets?: Record<string, IconifyJSON | IconifyJSONLoaderCallback>; | ||
} | ||
/** | ||
* All options | ||
*/ | ||
export declare interface IconifyPluginOptions extends IconCSSIconSetOptions, IconifyPluginFileOptions { | ||
} | ||
export { } |
@@ -10,3 +10,3 @@ /** | ||
* @license MIT | ||
* @version 0.0.2 | ||
* @version 0.1.0 | ||
*/ | ||
@@ -312,5 +312,2 @@ 'use strict'; | ||
const matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/; | ||
const missingIconsListError = 'TailwindCSS cannot dynamically find all used icons. Need to pass list of used icons to Iconify plugin.'; | ||
/** | ||
@@ -333,9 +330,36 @@ * Locate icon set | ||
/** | ||
* Cache for loaded icon sets | ||
* | ||
* Tailwind CSS can send multiple separate requests to plugin, this will | ||
* prevent same data from being loaded multiple times. | ||
* | ||
* Key is filename, not prefix! | ||
*/ | ||
const cache = Object.create(null); | ||
/** | ||
* Load icon set | ||
*/ | ||
function loadIconSet(prefix, options) { | ||
const filename = locateIconSet(prefix, options); | ||
// Check for custom icon set | ||
const customIconSet = options.iconSets?.[prefix]; | ||
if (customIconSet) { | ||
if (typeof customIconSet === 'function') { | ||
// Callback. Store result in options to avoid loading it again | ||
const result = customIconSet(); | ||
options.iconSets[prefix] = result; | ||
return result; | ||
} | ||
return customIconSet; | ||
} | ||
const filename = options.files?.[prefix] || locateIconSet(prefix, options); | ||
if (filename) { | ||
// Check for cache | ||
if (cache[filename]) { | ||
return cache[filename]; | ||
} | ||
// Attempt to load it | ||
try { | ||
return JSON.parse(fs.readFileSync(filename, 'utf8')); | ||
const result = JSON.parse(fs.readFileSync(filename, 'utf8')); | ||
cache[filename] = result; | ||
return result; | ||
} | ||
@@ -345,2 +369,5 @@ catch { } | ||
} | ||
const matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/; | ||
/** | ||
@@ -373,3 +400,3 @@ * Get icon names from list | ||
else { | ||
throw new Error(missingIconsListError); | ||
return; | ||
} | ||
@@ -406,10 +433,11 @@ // Parse array | ||
else { | ||
throw new Error(missingIconsListError); | ||
return; | ||
} | ||
return prefixes; | ||
} | ||
/** | ||
* Get CSS rules for icon | ||
* Get CSS rules for icons list | ||
*/ | ||
function getCSSRules(icons, options = {}) { | ||
function getCSSRulesForIcons(icons, options = {}) { | ||
const rules = Object.create(null); | ||
@@ -439,7 +467,57 @@ // Get all icons | ||
/** | ||
* Iconify plugin | ||
* Get dynamic CSS rules | ||
*/ | ||
function iconifyPlugin(icons, options = {}) { | ||
const rules = getCSSRules(icons, options); | ||
return plugin(({ addUtilities }) => { | ||
function getDynamicCSSRules(icon, options = {}) { | ||
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, | ||
}; | ||
} | ||
/** | ||
* Generate styles for dynamic selector: class="icon-[mdi-light--home]" | ||
*/ | ||
function addDynamicIconSelectors(options) { | ||
const prefix = options?.prefix || 'icon'; | ||
return plugin(({ matchComponents }) => { | ||
matchComponents({ | ||
[prefix]: (icon) => getDynamicCSSRules(icon, options), | ||
}); | ||
}); | ||
} | ||
/** | ||
* Generate styles for preset list of icons | ||
*/ | ||
function addCleanIconSelectors(icons, options) { | ||
const passedOptions = typeof icons === 'object' && !(icons instanceof Array) | ||
? icons | ||
: options || {}; | ||
const passedIcons = typeof icons !== 'object' || icons instanceof Array ? icons : void 0; | ||
// Get hardcoded list of icons | ||
const rules = passedIcons | ||
? getCSSRulesForIcons(passedIcons, passedOptions) | ||
: void 0; | ||
return plugin(({ addUtilities, matchComponents }) => { | ||
addUtilities(rules); | ||
@@ -449,2 +527,3 @@ }); | ||
module.exports = iconifyPlugin; | ||
exports.addCleanIconSelectors = addCleanIconSelectors; | ||
exports.addDynamicIconSelectors = addDynamicIconSelectors; |
@@ -5,3 +5,3 @@ { | ||
"author": "Vjacheslav Trushkin <cyberalien@gmail.com> (https://iconify.design)", | ||
"version": "0.0.2", | ||
"version": "0.1.0", | ||
"license": "MIT", | ||
@@ -8,0 +8,0 @@ "main": "./dist/plugin.js", |
@@ -10,19 +10,20 @@ # Iconify for Tailwind CSS | ||
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: | ||
To use icon in HTML, add class with class name like this: `icon-[mdi-light--home]` | ||
- Class name for icon set: `icon--{prefix}`. | ||
- Class name for icon: `icon--{prefix}--{name}`. | ||
```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 | ||
@@ -39,3 +40,3 @@ | ||
```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> | ||
``` | ||
@@ -60,6 +61,6 @@ | ||
```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`. | ||
@@ -75,4 +76,4 @@ Example: | ||
plugins: [ | ||
// Iconify plugin with list of icons you need | ||
iconifyPlugin(['mdi:home', 'mdi-light:account']), | ||
// Iconify plugin | ||
addDynamicIconSelectors(), | ||
], | ||
@@ -83,12 +84,35 @@ presets: [], | ||
### Icon names | ||
### Options | ||
Unfortunately Tailwind CSS cannot dynamically find all icon names. You need to specify list of icons you want to use. | ||
Plugin accepts options as a second parameter: | ||
### 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. | ||
Plugin accepts options as a second parameter. You can use it to change selectors. | ||
#### overrideOnly | ||
See [documentation for function used by plugin](https://docs.iconify.design/tools/utils/get-icons-css.html) for list of options. | ||
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 | ||
@@ -95,0 +119,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24647
636
123