Spinner: Fix so that the size property is correctly applied (#77135)

* correctly apply spinner sizes, refactor to have standard sizes

* better prop definitions so constant values show in IDEs

* 12 is xs, not sm
This commit is contained in:
Ashley Harrison
2023-10-25 15:39:32 +01:00
committed by GitHub
parent b88b206ee2
commit 5f2fd8935d
14 changed files with 105 additions and 35 deletions
@@ -58,14 +58,7 @@ export const Icon = React.forwardRef<SVGElement, IconProps>(
width={svgWid}
height={svgHgt}
title={title}
className={cx(
styles.icon,
{
'fa-spin': iconName === 'spinner',
},
className,
type === 'mono' ? { [styles.orange]: name === 'favorite' } : ''
)}
className={cx(styles.icon, className, type === 'mono' ? { [styles.orange]: name === 'favorite' } : '')}
style={style}
{...rest}
/>
@@ -49,7 +49,7 @@ export const Basic: Story<StoryProps> = (args) => {
Basic.args = {
backgroundColor: 'white',
color: 'red',
size: 34,
size: 'xl',
withStyle: false,
};
@@ -1,34 +1,108 @@
import { cx, css } from '@emotion/css';
import React from 'react';
import SVG from 'react-inlinesvg';
import { stylesFactory } from '../../themes';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { IconSize, isIconSize } from '../../types';
import { Icon } from '../Icon/Icon';
import { getIconRoot, getIconSubDir } from '../Icon/utils';
const getStyles = stylesFactory((size: number | string, inline: boolean) => {
return css([
{
fontSize: typeof size === 'string' ? size : `${size}px`,
},
inline && { display: 'inline-block' },
]);
});
export type Props = {
export interface Props {
className?: string;
style?: React.CSSProperties;
iconClassName?: string;
inline?: boolean;
size?: IconSize;
}
/**
* @deprecated
* use a predefined size, e.g. 'md' or 'lg' instead
*/
interface PropsWithDeprecatedSize extends Omit<Props, 'size'> {
size?: number | string;
};
}
/**
* @public
*/
export const Spinner = ({ className, inline = false, iconClassName, style, size = 16 }: Props) => {
const styles = getStyles(size, inline);
export const Spinner = ({
className,
inline = false,
iconClassName,
style,
size = 'md',
}: Props | PropsWithDeprecatedSize) => {
const styles = useStyles2(getStyles);
const deprecatedStyles = useStyles2(getDeprecatedStyles, size);
// this entire if statement is handling the deprecated size prop
// TODO remove once we fully remove the deprecated type
if (typeof size !== 'string' || !isIconSize(size)) {
const iconRoot = getIconRoot();
const iconName = 'spinner';
const subDir = getIconSubDir(iconName, 'default');
const svgPath = `${iconRoot}${subDir}/${iconName}.svg`;
return (
<div
data-testid="Spinner"
style={style}
className={cx(
{
[styles.inline]: inline,
},
deprecatedStyles.wrapper,
className
)}
>
<SVG
src={svgPath}
width={size}
height={size}
className={cx('fa-spin', deprecatedStyles.icon, className)}
style={style}
/>
</div>
);
}
return (
<div data-testid="Spinner" style={style} className={cx(styles, className)}>
<Icon className={cx('fa-spin', iconClassName)} name="spinner" aria-label="loading spinner" />
<div
data-testid="Spinner"
style={style}
className={cx(
{
[styles.inline]: inline,
},
className
)}
>
<Icon className={cx('fa-spin', iconClassName)} name="spinner" size={size} aria-label="loading spinner" />
</div>
);
};
const getStyles = (theme: GrafanaTheme2) => ({
inline: css({
display: 'inline-block',
}),
});
// TODO remove once we fully remove the deprecated type
const getDeprecatedStyles = (theme: GrafanaTheme2, size: number | string) => ({
wrapper: css({
fontSize: typeof size === 'string' ? size : `${size}px`,
}),
icon: css({
display: 'inline-block',
fill: 'currentColor',
flexShrink: 0,
label: 'Icon',
// line-height: 0; is needed for correct icon alignment in Safari
lineHeight: 0,
verticalAlign: 'middle',
}),
});
+3
View File
@@ -8,6 +8,9 @@ export { toIconName } from '@grafana/data';
export type IconType = 'mono' | 'default' | 'solid';
export type IconSize = ComponentSize | 'xl' | 'xxl' | 'xxxl';
export const isIconSize = (value: string): value is IconSize => {
return ['xs', 'sm', 'md', 'lg', 'xl', 'xxl', 'xxxl'].includes(value);
};
// function remains for backwards compatibility
export const getAvailableIcons = () => Object.keys(availableIconsIndex);