2024-04-15 09:18:56 +01:00
// @ts-check
const { ESLintUtils , AST _NODE _TYPES } = require ( '@typescript-eslint/utils' ) ;
const createRule = ESLintUtils . RuleCreator ( ( name ) => ` https://github.com/grafana/grafana/blob/main/packages/grafana-eslint-rules/README.md# ${ name } ` ) ;
const restrictedProperties = [ 'animation' , 'transition' ] ;
const isRestrictedProperty = ( /** @type string */ propertyName ) => {
return restrictedProperties . some ( ( prop ) => propertyName . startsWith ( prop ) ) ;
} ;
const rule = createRule ( {
create ( context ) {
return {
CallExpression ( node ) {
if (
node . callee . type === AST _NODE _TYPES . Identifier &&
node . callee . name === 'css'
) {
const cssObjects = node . arguments . flatMap ( ( node ) => {
switch ( node . type ) {
case AST _NODE _TYPES . ObjectExpression :
return [ node ] ;
case AST _NODE _TYPES . ArrayExpression :
return node . elements . filter ( v => v ? . type === AST _NODE _TYPES . ObjectExpression ) ;
default :
return [ ] ;
}
} ) ;
for ( const cssObject of cssObjects ) {
if ( cssObject ? . type === AST _NODE _TYPES . ObjectExpression ) {
for ( const property of cssObject . properties ) {
if (
property . type === AST _NODE _TYPES . Property &&
property . key . type === AST _NODE _TYPES . Identifier &&
isRestrictedProperty ( property . key . name )
) {
context . report ( {
node : property ,
messageId : 'noUnreducedMotion' ,
} ) ;
}
}
}
}
}
} ,
} ;
} ,
name : 'no-unreduced-motion' ,
meta : {
type : 'problem' ,
docs : {
description : 'Check if animation or transition properties are used directly.' ,
} ,
messages : {
2024-04-29 13:12:36 +01:00
noUnreducedMotion : 'Avoid direct use of `animation*` or `transition*` properties. Use the `handleMotion` utility function from theme.transitions or wrap in a `prefers-reduced-motion` media query.' ,
2024-04-15 09:18:56 +01:00
} ,
schema : [ ] ,
} ,
defaultOptions : [ ] ,
} ) ;
module . exports = rule ;