Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Javascript styling for Spinner",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "adrum@microsoft.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from 'react';
import { ISpinnerProps, ISpinnerStyleProps, ISpinnerStyles, SpinnerType, SpinnerSize } from './Spinner.types';
import {
BaseComponent,
customizable,
classNamesFunction,
DelayedRender,
getNativeProps,
divProperties
} from '../../Utilities';

const getClassNames = classNamesFunction<ISpinnerStyleProps, ISpinnerStyles>();

@customizable('Spinner', ['theme'])
export class SpinnerBase extends BaseComponent<ISpinnerProps, any> {

public static defaultProps: ISpinnerProps = {
size: SpinnerSize.medium,
ariaLive: 'polite'
};

public render() {
const {
type,
size,
ariaLabel,
ariaLive,
getStyles,
label,
theme,
className
} = this.props;
const statusMessage = ariaLabel || label;
const nativeProps = getNativeProps(this.props, divProperties, ['size']);

// SpinnerType is deprecated. If someone is still using this property, rather than putting the SpinnerType into the ISpinnerStyleProps,
// we'll map SpinnerType to its equivalent SpinnerSize and pass that in. Once SpinnerType finally goes away we should delete this.
let styleSize = size;
if (styleSize === undefined && type !== undefined) {
styleSize = type === SpinnerType.large ? SpinnerSize.large : SpinnerSize.medium;
}

const classNames = getClassNames(getStyles!, {
theme: theme!,
size: styleSize,
className
});

return (
<div { ...nativeProps } className={ classNames.root }>
<div className={ classNames.circle } />
{
label && <div className={ classNames.label }>{ label }</div>
}
{
statusMessage &&
<div role='status' aria-live={ ariaLive }>
<DelayedRender>
<div className={ classNames.screenReaderText }>{ statusMessage }</div>
</DelayedRender>
</div>
}
</div>
);
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { ISpinnerStyleProps, ISpinnerStyles, SpinnerSize, SpinnerType } from './Spinner.types';
import { IRawStyle, hiddenContentStyle, keyframes, HighContrastSelector } from '../../Styling';

const spinAnimation: string = keyframes({
'0%': {
transform: 'rotateZ(0deg)'
},
'100%': {
transform: 'rotateZ(360deg)'
}
});

export const getStyles = (props: ISpinnerStyleProps): ISpinnerStyles => {
const { theme, size, className } = props;
const { palette } = theme;

return {
root: [
'ms-Spinner',
className
],
circle: [
'ms-Spinner-circle',
{
margin: 'auto',
boxSizing: 'border-box',
borderRadius: '50%',
width: '100%',
height: '100%',
border: '1.5px solid ' + palette.themeLight,
borderTopColor: palette.themePrimary,
animationName: spinAnimation,
animationDuration: '1.3s',
animationIterationCount: 'infinite',
animationTimingFunction: 'cubic-bezier(.53,.21,.29,.67)',
selectors: {
[HighContrastSelector]: {
borderTopColor: 'Highlight'
}
},
},
size === SpinnerSize.xSmall && [
'ms-Spinner--xSmall',
{
width: 12,
height: 12
}
],
size === SpinnerSize.small && [
'ms-Spinner--small',
{
width: 16,
height: 16
}
],
size === SpinnerSize.medium && [
'ms-Spinner--medium',
{
width: 20,
height: 20
}
],
size === SpinnerSize.large && [
'ms-Spinner--large',
{
width: 28,
height: 28
}
]
],
label: [
'ms-Spinner-label',
{
color: palette.themePrimary,
marginTop: 10,
textAlign: 'center'
}
],
screenReaderText: hiddenContentStyle
};
};
Original file line number Diff line number Diff line change
@@ -1,45 +1,9 @@
import * as React from 'react';
import { BaseComponent, css, DelayedRender } from '../../Utilities';
import { ISpinnerProps, SpinnerType, SpinnerSize } from './Spinner.types';
import * as stylesImport from './Spinner.scss';
const styles: any = stylesImport;
import { styled } from '../../Utilities';
import { SpinnerBase } from './Spinner.base';
import { ISpinnerProps } from './Spinner.types';
import { getStyles } from './Spinner.styles';

export class Spinner extends BaseComponent<ISpinnerProps, any> {
public static defaultProps: ISpinnerProps = {
size: SpinnerSize.medium,
ariaLive: 'polite'
};

public render() {
const { type, size, label, className, ariaLive, ariaLabel } = this.props; // TODO remove deprecated type property at >= 2.0.0
const statusMessage = ariaLabel || label;

return (
<div className={ css('ms-Spinner', styles.root, className) }>
<div
className={ css('ms-Spinner-circle', styles.circle,
{
['ms-Spinner--xSmall ' + styles.circleIsXSmall]: size === SpinnerSize.xSmall,
['ms-Spinner--small ' + styles.circleIsSmall]: size === SpinnerSize.small,
['ms-Spinner--medium ' + styles.circleIsMedium]: size === SpinnerSize.medium,
['ms-Spinner--large ' + styles.circleIsLarge]: size === SpinnerSize.large,
['ms-Spinner--normal ' + styles.circleIsTypeMedium]: type === SpinnerType.normal, // TODO remove deprecated value at >= 2.0.0
['ms-Spinner--large ' + styles.circleIsTypeLarge]: type === SpinnerType.large // TODO remove deprecated value at >= 2.0.0
})
}
/>
{
label && <div className={ css('ms-Spinner-label', styles.label) }>{ label }</div>
}
{
statusMessage &&
<div role='status' aria-live={ ariaLive }>
<DelayedRender>
<div className={ styles.screenReaderOnly }>{ statusMessage }</div>
</DelayedRender>
</div>
}
</div>
);
}
}
export const Spinner = styled(
SpinnerBase,
getStyles
);
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as React from 'react';
import { Spinner } from './Spinner';
import { ITheme, IStyle, IRawStyle } from '../../Styling';
import { IStyleFunction } from '../../Utilities';

export interface ISpinner {

}

export interface ISpinnerProps extends React.Props<Spinner> {
export interface ISpinnerProps extends React.HTMLAttributes<HTMLElement> {
/**
* Optional callback to access the ISpinner interface. Use this instead of ref for accessing
* the public methods and properties of the component.
Expand Down Expand Up @@ -45,6 +47,16 @@ export interface ISpinnerProps extends React.Props<Spinner> {
* Alternative status label for screen reader
*/
ariaLabel?: string;

/**
* Theme (provided through customization.)
*/
theme?: ITheme;

/**
* Call to provide customized styling that will layer on top of the variant rules.
*/
getStyles?: IStyleFunction<ISpinnerStyleProps, ISpinnerStyles>;
}

export enum SpinnerSize {
Expand Down Expand Up @@ -84,3 +96,16 @@ export enum SpinnerType {
*/
large = 1
}

export interface ISpinnerStyleProps {
theme: ITheme;
size?: SpinnerSize;
className?: string;
}

export interface ISpinnerStyles {
root?: IStyle;
circle?: IStyle;
label?: IStyle;
screenReaderText?: IStyle;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
:global {
.ms-BasicSpinnersExample .ms-Spinner {
display: inline-block;
.ms-BasicSpinnersExample {
margin: 10px 0;
width: 300px;
}
}