GLDS: Check if tokens are used as borderRadius values (#71187)

This commit is contained in:
Laura Fernández 2023-08-01 12:44:25 +02:00 committed by GitHub
parent de6ef53c8a
commit 7469f58709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 83 additions and 11 deletions

View File

@ -7,6 +7,7 @@
"import/external-module-folders": ["node_modules", ".yarn"]
},
"rules": {
"@grafana/no-border-radius-literal": "error",
"react/prop-types": "off",
// need to ignore emotion's `css` prop, see https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md#rule-options
"react/no-unknown-property": ["error", { "ignore": ["css"] }],

View File

@ -12,6 +12,12 @@ Previously we hijacked the aria-label property to use as E2E selectors as an att
Now, we prefer using data-testid for E2E selectors.
### `@grafana/no-border-radius-literal`
Check if border-radius theme tokens are used.
To improve the consistency across Grafana we encourage devs to use tokens instead of custom values. In this case, we want the `borderRadius` to use the appropiate token such as `theme.shape.radius.default`, `theme.shape.radius.pill` or `theme.shape.radius.circle`.
### `@grafana/theme-token-usage`
Used to find all instances of `theme` tokens being used in the codebase and emit the counts as metrics. Should **not** be used as an actual lint rule!

View File

@ -1,9 +1,11 @@
const noAriaLabelSelectors = require('./rules/no-aria-label-e2e-selectors.cjs');
const noBorderRadiusLiteral = require('./rules/no-border-radius-literal.cjs');
const themeTokenUsage = require('./rules/theme-token-usage.cjs');
module.exports = {
rules: {
'no-aria-label-selectors': noAriaLabelSelectors,
'no-border-radius-literal': noBorderRadiusLiteral,
'theme-token-usage': themeTokenUsage,
},
};

View File

@ -0,0 +1,61 @@
// @ts-check
const { ESLintUtils, AST_NODE_TYPES } = require('@typescript-eslint/utils');
const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/grafana/grafana#${name}`);
const borderRadiusRule = 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 &&
property.key.name === 'borderRadius' &&
property.value.type === AST_NODE_TYPES.Literal
) {
context.report({
node: property,
messageId: 'borderRadiusId',
});
}
}
}
}
}
},
};
},
name: 'no-border-radius-literal',
meta: {
type: 'problem',
docs: {
description: 'Check if border-radius theme tokens are used',
recommended: false,
},
messages: {
borderRadiusId: 'Prefer using theme.shape.radius tokens instead of literal values.',
},
schema: [],
},
defaultOptions: [],
});
module.exports = borderRadiusRule;

View File

@ -71,7 +71,8 @@ export const getStyles = (theme: GrafanaTheme2) => {
boxShadow: theme.shadows.z3,
backgroundColor: theme.colors.background.primary,
border: `1px solid ${theme.colors.border.weak}`,
borderRadius: '2px 0 0 2px',
borderTopLeftRadius: theme.shape.radius.default,
borderBottomLeftRadius: theme.shape.radius.default,
'button:disabled': {
color: theme.colors.text.disabled,

View File

@ -24,7 +24,8 @@ export const getStyles = (theme: GrafanaTheme2, isReversed = false) => {
backgroundColor: theme.colors.background.primary,
zIndex: -1,
border: `1px solid ${theme.colors.border.weak}`,
borderRadius: '2px 0 0 2px',
borderTopLeftRadius: theme.shape.radius.default,
borderBottomLeftRadius: theme.shape.radius.default,
'&:after': {
display: 'block',

View File

@ -268,7 +268,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme2, isReversed, hideQuickRang
background: theme.colors.background.primary,
boxShadow: theme.shadows.z3,
width: `${isFullscreen ? '546px' : '262px'}`,
borderRadius: '2px',
borderRadius: theme.shape.radius.default,
border: `1px solid ${theme.colors.border.weak}`,
[`${isReversed ? 'left' : 'right'}`]: 0,
}),

View File

@ -52,7 +52,7 @@ const getStyles = (theme: GrafanaTheme2) => {
color: theme.colors.text.primary,
background: theme.colors.background.secondary,
padding: '2px 5px',
borderRadius: '2px',
borderRadius: theme.shape.radius.default,
marginLeft: '4px',
}),
};

View File

@ -303,7 +303,7 @@ function getStyles(theme: GrafanaTheme2, isDragActive?: boolean) {
flexDirection: 'column',
width: '100%',
padding: theme.spacing(2),
borderRadius: '2px',
borderRadius: theme.shape.radius.default,
border: `1px dashed ${theme.colors.border.strong}`,
backgroundColor: isDragActive ? theme.colors.background.secondary : theme.colors.background.primary,
cursor: 'pointer',

View File

@ -63,7 +63,7 @@ const getStyles = (theme: GrafanaTheme2) => {
background: theme.components.tooltip.background,
color: theme.components.tooltip.text,
padding: theme.spacing(0.5, 1.5), // get's an extra .5 of vertical padding to account for the rounded corners
borderRadius: 100, // just a sufficiently large value to ensure ends are completely rounded
borderRadius: theme.shape.radius.circle,
display: 'inline-flex',
gap: theme.spacing(0.5),
alignItems: 'center',

View File

@ -31,7 +31,7 @@ const getStyles = (theme: GrafanaTheme2) => {
width: '400px',
height: '200px',
border: `1px solid ${borderColor}`,
borderRadius: '3px',
borderRadius: theme.shape.radius.default,
}),
};
};

View File

@ -230,7 +230,7 @@ export function RichColorDemo({ theme, color }: RichColorDemoProps) {
<div
className={css({
background: color.main,
borderRadius: theme.shape.borderRadius(),
borderRadius: theme.shape.radius.default,
color: color.contrastText,
padding: '8px',
fontWeight: 500,
@ -244,7 +244,7 @@ export function RichColorDemo({ theme, color }: RichColorDemoProps) {
className={css({
background: color.shade,
color: color.contrastText,
borderRadius: '4px',
borderRadius: theme.shape.radius.default,
padding: '8px',
})}
>
@ -255,7 +255,7 @@ export function RichColorDemo({ theme, color }: RichColorDemoProps) {
<div
className={css({
background: color.transparent,
borderRadius: '4px',
borderRadius: theme.shape.radius.default,
padding: '8px',
})}
>
@ -267,7 +267,7 @@ export function RichColorDemo({ theme, color }: RichColorDemoProps) {
className={css({
border: `1px solid ${color.border}`,
color: color.text,
borderRadius: '4px',
borderRadius: theme.shape.radius.default,
padding: '8px',
})}
>