UNPKG

eslint-plugin-better-tailwindcss

Version:

auto-wraps tailwind classes after a certain print width or class count into multiple lines to improve readability.

76 lines 3.41 kB
import { array, boolean, description, optional, pipe, strictObject, string } from "valibot"; import { createGetDissectedClasses, getDissectedClasses } from "../tailwindcss/dissect-classes.js"; import { async } from "../utils/context.js"; import { lintClasses } from "../utils/lint.js"; import { getCachedRegex } from "../async-utils/regex.js"; import { createRule } from "../utils/rule.js"; import { splitClasses } from "../utils/utils.js"; export const enforceMotionSafeVariant = createRule({ autofix: false, category: "correctness", description: "Enforce the 'motion-safe' variant for transition and animation classes.", docs: "https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/main/docs/rules/enforce-motion-safe-variant.md", name: "enforce-motion-safe-variant", recommended: false, messages: { missing: "{{ className }} is missing the 'motion-safe' variant." }, schema: strictObject({ classes: optional(pipe(array(string()), description("A list of regular expression patterns for classes that require the 'motion-safe' variant.")), ["^transition(-.*)?$", "^animate(-.*)?$"]), motionReduce: optional(pipe(boolean(), description("Suppress warnings for a literal that already contains a class with the 'motion-reduce' variant (in itself or in prior literals).")), false) }), initialize: ctx => { createGetDissectedClasses(ctx); }, lintLiterals: (ctx, literals) => lintLiterals(ctx, literals) }); function lintLiterals(ctx, literals) { const { classes: classPatterns, motionReduce } = ctx.options; for (const literal of literals) { const classes = splitClasses(literal.content); const { dissectedClasses, warnings } = getDissectedClasses(async(ctx), classes); if (motionReduce && hasMotionReduceVariant(ctx, literal, dissectedClasses)) { continue; } lintClasses(ctx, literal, className => { const dissectedClass = dissectedClasses[className]; if (dissectedClass?.variants === undefined) { return; } if (!classPatterns.some(pattern => getCachedRegex(pattern).test(dissectedClass.base))) { return; } if (dissectedClass.variants.includes("motion-safe") || dissectedClass.variants.includes("motion-reduce")) { return; } return { data: { className }, id: "missing", warnings }; }); } } function hasMotionReduceVariant(ctx, literal, dissectedClasses) { if (hasMotionReduceInClasses(dissectedClasses)) { return true; } if (!literal.priorLiterals) { return false; } for (const priorLiteral of literal.priorLiterals) { if (!priorLiteral) { continue; } const priorClasses = splitClasses(priorLiteral.content); const { dissectedClasses: priorDissectedClasses } = getDissectedClasses(async(ctx), priorClasses); if (hasMotionReduceInClasses(priorDissectedClasses)) { return true; } } return false; } function hasMotionReduceInClasses(dissectedClasses) { return Object.values(dissectedClasses).some(dissectedClass => dissectedClass.variants?.includes("motion-reduce")); } //# sourceMappingURL=enforce-motion-safe-variant.js.map