/** * @module @twind/preset-tailwind/variants */ import type { AutocompleteProvider, VariantResolver, Variant, AutocompleteItem } from '@twind/core' import type { TailwindTheme } from './types' import { DEV } from 'distilt/env' import { normalize, withAutocomplete } from '@twind/core' // indirection wrapper to remove autocomplete functions from production bundles function withAutocomplete$( rule: VariantResolver, autocomplete: AutocompleteProvider | false, ): VariantResolver { if (DEV) { return withAutocomplete(rule, autocomplete) } return rule } const variants: Variant[] = [ ['sticky', '@supports ((position: -webkit-sticky) or (position:sticky))'], ['motion-reduce', '@media (prefers-reduced-motion:reduce)'], ['motion-safe', '@media (prefers-reduced-motion:no-preference)'], ['print', '@media print'], ['portrait', '@media (orientation:portrait)'], ['landscape', '@media (orientation:landscape)'], ['contrast-more', '@media (prefers-contrast:more)'], ['contrast-less', '@media (prefers-contrast:less)'], ['marker', '& *::marker,&::marker'], ['selection', '& *::selection,&::selection'], // TODO: use pseudoElement helper? ['first-letter', '&::first-letter'], ['first-line', '&::first-line'], ['file', '&::file-selector-button'], ['placeholder', '&::placeholder'], ['backdrop', '&::backdrop'], ['first', '&:first-child'], ['last', '&:last-child'], ['even', '&:nth-child(2n)'], ['odd', '&:nth-child(odd)'], ['open', '&[open]'], // All other pseudo classes are already supported by twind /* Styling based on parent and peer state */ // Groups classes like: group-focus and group-hover // these need to add a marker selector with the pseudo class // => '.group:focus .group-focus:selector' [ '((group|peer)(~[^-[]+)?)(-[a-z-]+|-\\[(.+)]|\\[.+])', withAutocomplete$( ({ 1: $1, 4: $4, 5: $5 }, { e, h, v }) => { const selector = ($5 && normalize($5)) || ($4[0] == '[' ? $4 : (v($4.slice(1)) as string)) // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access return `${(selector.includes('&') ? selector : '&' + selector).replace( /&/g, `:merge(.${e(h($1))})`, )}${$1[0] == 'p' ? '~' : ' '}&` }, DEV && ((_, { variants }) => [...Object.entries(variants)] .filter(([, selector]) => /^&(\[|:[^:])/.test(selector)) .flatMap(([variant, selector]): AutocompleteItem[] => [ { prefix: 'group-', suffix: variant, label: `${selector.replace('&', '.group')} &` }, { prefix: 'peer-', suffix: variant, label: `${selector.replace('&', '.peer')} &` }, ])), ), ], // direction variants [ '(ltr|rtl)', withAutocomplete$( ({ 1: $1 }) => `[dir="${$1}"] &`, DEV && (({ 1: $1 }) => [{ prefix: $1, suffix: '', label: `[dir="${$1}"] &` }]), ), ], // Arbitrary variants [/^\[(.+)]$/, ({ 1: $1 }) => /[&@]/.test($1) && normalize($1).replace(/[}]+$/, '').split('{')], ] export default variants