mirror of
				https://github.com/grafana/grafana.git
				synced 2025-02-25 18:55:37 -06:00 
			
		
		
		
	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:
		@@ -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',
 | 
			
		||||
  }),
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -156,7 +156,7 @@ export const RolePicker = ({
 | 
			
		||||
    return (
 | 
			
		||||
      <div style={{ maxWidth: widthPx || maxWidth, width: widthPx }}>
 | 
			
		||||
        <span>Loading...</span>
 | 
			
		||||
        <Spinner size={16} inline className={styles.loadingSpinner} />
 | 
			
		||||
        <Spinner inline className={styles.loadingSpinner} />
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@ export const CloudRules = ({ namespaces, expandAll }: Props) => {
 | 
			
		||||
 | 
			
		||||
      {!hasDataSourcesConfigured && <p>There are no Prometheus or Loki data sources configured.</p>}
 | 
			
		||||
      {hasDataSourcesConfigured && !hasDataSourcesLoading && !hasNamespaces && <p>No rules found.</p>}
 | 
			
		||||
      {!hasSomeResults && hasDataSourcesLoading && <Spinner size={24} className={styles.spinner} />}
 | 
			
		||||
      {!hasSomeResults && hasDataSourcesLoading && <Spinner size="xl" className={styles.spinner} />}
 | 
			
		||||
 | 
			
		||||
      <Pagination
 | 
			
		||||
        className={styles.pagination}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ export const GrafanaRules = ({ namespaces, expandAll }: Props) => {
 | 
			
		||||
        />
 | 
			
		||||
      ))}
 | 
			
		||||
      {hasResult && namespacesFormat?.length === 0 && <p>No rules found.</p>}
 | 
			
		||||
      {!hasResult && loading && <Spinner size={24} className={styles.spinner} />}
 | 
			
		||||
      {!hasResult && loading && <Spinner size="xl" className={styles.spinner} />}
 | 
			
		||||
      <Pagination
 | 
			
		||||
        className={styles.pagination}
 | 
			
		||||
        currentPage={page}
 | 
			
		||||
 
 | 
			
		||||
@@ -174,7 +174,7 @@ export const GenAIButton = ({
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={styles.wrapper}>
 | 
			
		||||
      {isFirstHistoryEntry && <Spinner size={14} />}
 | 
			
		||||
      {isFirstHistoryEntry && <Spinner size="sm" />}
 | 
			
		||||
      {!hasHistory && (
 | 
			
		||||
        <Tooltip
 | 
			
		||||
          show={error ? undefined : false}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ export function SettingsSummary({
 | 
			
		||||
 | 
			
		||||
  return isDataLoading ? (
 | 
			
		||||
    <div className={cx(styles.summaryWrapper, className)}>
 | 
			
		||||
      <Spinner className={styles.summary} inline={true} size={14} />
 | 
			
		||||
      <Spinner className={styles.summary} inline={true} size="sm" />
 | 
			
		||||
    </div>
 | 
			
		||||
  ) : (
 | 
			
		||||
    <div className={cx(styles.summaryWrapper, className)}>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ const Loader = () => {
 | 
			
		||||
    <HorizontalGroup className={styles.loadingContainer}>
 | 
			
		||||
      <>
 | 
			
		||||
        Loading configuration
 | 
			
		||||
        <Spinner size={20} className={styles.spinner} />
 | 
			
		||||
        <Spinner size="lg" className={styles.spinner} />
 | 
			
		||||
      </>
 | 
			
		||||
    </HorizontalGroup>
 | 
			
		||||
  );
 | 
			
		||||
 
 | 
			
		||||
@@ -238,7 +238,7 @@ class UnthemedDashboardImport extends PureComponent<Props> {
 | 
			
		||||
          {loadingState === LoadingState.Loading && (
 | 
			
		||||
            <VerticalGroup justify="center">
 | 
			
		||||
              <HorizontalGroup justify="center">
 | 
			
		||||
                <Spinner size={32} />
 | 
			
		||||
                <Spinner size="xxl" />
 | 
			
		||||
              </HorizontalGroup>
 | 
			
		||||
            </VerticalGroup>
 | 
			
		||||
          )}
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ export function QueryValidator({ db, query, onValidate, range }: QueryValidatorP
 | 
			
		||||
    <>
 | 
			
		||||
      {state.loading && (
 | 
			
		||||
        <div className={styles.info}>
 | 
			
		||||
          <Spinner inline={true} size={12} /> Validating query...
 | 
			
		||||
          <Spinner inline={true} size="xs" /> Validating query...
 | 
			
		||||
        </div>
 | 
			
		||||
      )}
 | 
			
		||||
      {!state.loading && state.value && (
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ export function VariablesUnknownTable({ variables, dashboard }: VariablesUnknown
 | 
			
		||||
          <VerticalGroup justify="center">
 | 
			
		||||
            <HorizontalGroup justify="center">
 | 
			
		||||
              <span>Loading...</span>
 | 
			
		||||
              <Spinner size={16} />
 | 
			
		||||
              <Spinner />
 | 
			
		||||
            </HorizontalGroup>
 | 
			
		||||
          </VerticalGroup>
 | 
			
		||||
        )}
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,7 @@ export class GettingStarted extends PureComponent<PanelProps, State> {
 | 
			
		||||
        {!checksDone ? (
 | 
			
		||||
          <div className={styles.loading}>
 | 
			
		||||
            <div className={styles.loadingText}>Checking completed setup steps</div>
 | 
			
		||||
            <Spinner size={24} inline />
 | 
			
		||||
            <Spinner size="xl" inline />
 | 
			
		||||
          </div>
 | 
			
		||||
        ) : (
 | 
			
		||||
          <>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user