Skip to content

Commit

Permalink
feat(inline-spinner): add experimental component (#503)
Browse files Browse the repository at this point in the history
* feat(icons): add experimental spinner icon

* feat(inline-spinner): add experimental component

* feat(button): use experimental inline-spinner

* feat(icon-button): use experimental inline-spinner

---------

Co-authored-by: Lena Rashkovan <[email protected]>
  • Loading branch information
alatielle and Lena Rashkovan authored Dec 4, 2024
1 parent 0654e16 commit 1b198fa
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 8 deletions.
3 changes: 3 additions & 0 deletions assets/icons/experimental/spinner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions src/components/experimental/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button as BaseButton, ButtonProps as BaseButtonProps } from 'react-aria
import { getSemanticValue } from '../../../essentials/experimental/cssVariables';
import { get } from '../../../utils/experimental/themeGet';
import { textStyles } from '../Text/Text';
import { InlineSpinner } from '../../InlineSpinner/InlineSpinner';
import { InlineSpinner } from '../InlineSpinner/InlineSpinner';

type Emphasis = 'primary' | 'secondary' | 'textButton';

Expand Down Expand Up @@ -129,7 +129,11 @@ const spinnerColor: Record<Emphasis, string> = {
function Button({ children, emphasis = 'primary', isLoading = false, ...restProps }: ButtonProps): ReactElement {
return (
<ButtonStyled data-testid="button-container" isPending={isLoading} $emphasis={emphasis} {...restProps}>
{isLoading ? <InlineSpinner data-testid="button-spinner" color={spinnerColor[emphasis]} /> : children}
{isLoading ? (
<InlineSpinner data-testid="button-spinner" color={spinnerColor[emphasis]} size="medium" />
) : (
children
)}
</ButtonStyled>
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/experimental/IconButton/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styled from 'styled-components';
import { ButtonProps, Button } from 'react-aria-components';
import { IconProps } from '../../../icons';
import { getSemanticValue } from '../../../essentials/experimental';
import { InlineSpinner } from '../../InlineSpinner/InlineSpinner';
import { InlineSpinner } from '../InlineSpinner/InlineSpinner';

export interface IconButtonProps extends ButtonProps {
isActive?: boolean;
Expand Down Expand Up @@ -123,7 +123,7 @@ export const IconButton = ({
{...restProps}
>
{isLoading ? (
<InlineSpinner data-testid="iconbutton-spinner" color={getSemanticValue('on-surface')} />
<InlineSpinner data-testid="iconbutton-spinner" color={getSemanticValue('on-surface')} size="medium" />
) : (
<Icon data-testid="iconbutton-icon" />
)}
Expand Down
67 changes: 67 additions & 0 deletions src/components/experimental/InlineSpinner/InlineSpinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from 'react';
import styled, { keyframes } from 'styled-components';
import { compose, variant } from 'styled-system';
import SpinnerIcon from '../../../icons/experimental/SpinnerIcon';
import { getSemanticValue } from '../../../essentials/experimental';

interface InlineSpinnerProps {
/**
* Override the color of the spinner
*/
color?: string;
/**
* Set the size of the component
*/
size?: 'small' | 'medium' | 'large';
}

const sizeVariant = variant({
prop: 'size',
variants: {
small: {
width: '1rem',
height: '1rem'
},
medium: {
width: '1.25rem',
height: '1.25rem'
},
large: {
width: '2.5rem',
height: '2.5rem'
}
}
});

const rotation = keyframes`
to {
transform: rotate(360deg);
}
`;

const Wrapper = styled.span<InlineSpinnerProps>`
display: inline-flex;
box-sizing: border-box;
vertical-align: text-bottom;
${compose(sizeVariant)}
`;

const Icon = styled(SpinnerIcon)`
width: 100%;
height: 100%;
animation: ${rotation} 750ms linear infinite;
`;

const InlineSpinner: React.FC<InlineSpinnerProps> = ({
color = getSemanticValue('interactive'),
size = 'medium',
...rest
}: InlineSpinnerProps) => (
<Wrapper aria-busy="true" size={size}>
<Icon color={color} {...rest} />
</Wrapper>
);

export { InlineSpinner, InlineSpinnerProps };
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Meta, StoryObj } from '@storybook/react';
import { InlineSpinner } from '../InlineSpinner';

const meta: Meta = {
title: 'Experimental/Components/InlineSpinner',
component: InlineSpinner,
parameters: {
layout: 'centered'
},
argTypes: {
size: {
control: 'radio',
options: ['large', 'medium', 'small']
}
}
};

export default meta;

type Story = StoryObj<typeof InlineSpinner>;

export const Default: Story = {};
1 change: 1 addition & 0 deletions src/components/experimental/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { DatePicker } from './DatePicker/DatePicker';
export { Dialog } from './Dialog/Dialog';
export { Divider } from './Divider/Divider';
export { IconButton } from './IconButton/IconButton';
export { InlineSpinner } from './InlineSpinner/InlineSpinner';
export { Label } from './Label/Label';
export { ListBox, ListBoxItem } from './ListBox/ListBox';
export { Popover } from './Popover/Popover';
Expand Down
27 changes: 27 additions & 0 deletions src/icons/experimental/SpinnerIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// DO NOT EDIT. This file was generated by running `npm run generate`.;
import * as React from 'react';
import { get } from '../../utils/themeGet';
import { IconProps } from '../IconProps';
type Props = IconProps;
const SpinnerIcon: React.FC<Props> = ({ size = 'medium', color = 'inherit', ...rest }) => {
const props = { ...rest, color };
const sizePx = Number.isFinite(size as number)
? size
: get(`iconSizes.${size}`)(props) || get('iconSizes.medium')(props);
return (
<svg
{...props}
width={sizePx}
height={sizePx}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 16.482a6.482 6.482 0 010-12.963V1.667A8.333 8.333 0 1018.333 10h-1.852A6.482 6.482 0 0110 16.482z"
fill="currentColor"
/>
</svg>
);
};
export default SpinnerIcon;
9 changes: 5 additions & 4 deletions src/icons/experimental/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as CalendarTodayOutlineIcon } from './CalendarTodayOutlineIcon';
export { default as AccountOutlineIcon } from "./AccountOutlineIcon";
export { default as CarGroupOutlineIcon } from "./CarGroupOutlineIcon";
export { default as CarOutlineIcon } from "./CarOutlineIcon";
export { default as LocationIcon } from "./LocationIcon";
export { default as AccountOutlineIcon } from './AccountOutlineIcon';
export { default as CarGroupOutlineIcon } from './CarGroupOutlineIcon';
export { default as CarOutlineIcon } from './CarOutlineIcon';
export { default as LocationIcon } from './LocationIcon';
export { default as SpinnerIcon } from './SpinnerIcon';

0 comments on commit 1b198fa

Please sign in to comment.