import plugin from "tailwindcss/plugin"; type MaybeString = string | null | undefined; type UtilType = "group" | "peer"; // Main plugin export default plugin(function ({ matchVariant, theme, e }) { const values = { values: { DEFAULT: "", ...theme("betterStates", {}), }, }; const selector = (state: string, prefix: MaybeString) => { return `${prefix ?? "&"}:${state}:not(:disabled)`; }; const maybeWrap = (state: string, prefix = "&", value: MaybeString) => { return ["", null, undefined].includes(value) ? selector(state, prefix) : `${prefix}:has(${selector(state, value)})`; }; const merge = ( type: UtilType, value: MaybeString, modifier: string | null, callback: (value: MaybeString, prefix: string) => string[] ) => { const typeClass = modifier ? `.${type}\\/${e(modifier)}` : `.${type}`; const append = type === "group" ? " &" : " ~ &"; return callback(value, `:merge(${typeClass})`).map((x) => `${x}${append}`); }; // Hovered ________________________________________________________________________ const hovered = (value: MaybeString = null, prefix = "&") => [ maybeWrap("focus-visible", prefix, value), maybeWrap("hover", prefix, value), maybeWrap("has(:focus-visible)", prefix, value), ]; matchVariant("hovered", (value) => hovered(value), values); matchVariant( "group-hovered", (value, { modifier }) => merge("group", value, modifier, hovered), values ); matchVariant( "peer-hovered", (value, { modifier }) => merge("peer", value, modifier, hovered), values ); // Pressed ________________________________________________________________________ const pressed = (value: MaybeString = null, prefix = "&") => [ maybeWrap("active", prefix, value), maybeWrap("has(:active)", prefix, value), `@media (hover: none) { ${maybeWrap("hover", prefix, value)} }`, `@media (hover: none) { ${maybeWrap("focus", prefix, value)} }`, ]; matchVariant("pressed", (value) => pressed(value), values); matchVariant( "group-pressed", (value, { modifier }) => merge("group", value, modifier, pressed), values ); matchVariant( "peer-pressed", (value, { modifier }) => merge("peer", value, modifier, pressed), values ); });