import plugin from 'tailwindcss/plugin'
import { getIconsCSSData } from '@iconify/utils/lib/css/icons'
import { loadIconSet } from '@iconify/tailwind4/lib/helpers/loader.js'
import { matchIconName } from '@iconify/utils/lib/icon/name'
/**
* Tailwind 4 plugin that provides lucide icon variants with configurable
* stroke-width via class prefix.
*
* Usage in CSS:
* @plugin "./lucideStrokePlugin.js";
*
* Usage in templates:
*
*
*
*
* The default class remains stroke-width: 2.
*/
const STROKE_WIDTHS = ['1', '1.3', '1.5', '2', '2.5']
const SCALE = 1.2
function getDynamicCSSRulesWithStroke(icon, strokeWidth) {
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)
if (!iconSet) {
throw new Error(
`Cannot load icon set for "${prefix}". Install "@iconify-json/${prefix}" as dev dependency?`
)
}
const generated = getIconsCSSData(iconSet, [name], {
iconSelector: '.icon',
customise: (content) =>
content.replaceAll('stroke-width="2"', `stroke-width="${strokeWidth}"`)
})
if (generated.css.length !== 1) {
throw new Error(`Cannot find "${icon}". Bad icon name?`)
}
if (SCALE && generated.common?.rules) {
generated.common.rules.height = SCALE + 'em'
generated.common.rules.width = SCALE + 'em'
}
return {
...generated.common?.rules,
...generated.css[0].rules
}
}
export default plugin(({ matchComponents }) => {
for (const sw of STROKE_WIDTHS) {
matchComponents({
[`icon-s${sw}`]: (icon) => {
try {
return getDynamicCSSRulesWithStroke(icon, sw)
} catch (err) {
console.warn(err.message)
return {}
}
}
})
}
})