|
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-visible', prefix, value)} & }`, |
|
`@media (hover: none) { ${maybeWrap('has(:focus-visible)', prefix, value)} & }`, |
|
`@media (hover: none) { ${maybeWrap('focus', prefix, value)} & }`, |
|
`@media (hover: none) { ${maybeWrap('has(: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 |
|
); |
|
}); |