Replace spin.js with a CSS-only loading spinner (#2764)

* Create CSS only loading indicator

* Core mods to fix Loading Indicator usage

* Remove extra whitespace

* Attrs interface extends ComponentAttrs and is exported

* Add doc block about custom styling
This commit is contained in:
David Wheatley 2021-04-09 00:42:32 +01:00 committed by GitHub
parent 84e12a4864
commit 734ea42ff6
6 changed files with 140 additions and 60 deletions

View File

@ -1,43 +0,0 @@
import Component from '../Component';
import { Spinner } from 'spin.js';
/**
* The `LoadingIndicator` component displays a loading spinner with spin.js.
*
* ### Attrs
*
* - `size` The spin.js size preset to use. Defaults to 'small'.
*
* All other attrs will be assigned as attributes on the DOM element.
*/
export default class LoadingIndicator extends Component {
view() {
const attrs = Object.assign({}, this.attrs);
attrs.className = 'LoadingIndicator ' + (attrs.className || '');
delete attrs.size;
return <div {...attrs}>{m.trust('&nbsp;')}</div>;
}
oncreate(vnode) {
super.oncreate(vnode);
const options = { zIndex: 'auto', color: this.$().css('color') };
switch (this.attrs.size) {
case 'large':
Object.assign(options, { lines: 10, length: 8, width: 4, radius: 8 });
break;
case 'tiny':
Object.assign(options, { lines: 8, length: 2, width: 2, radius: 3 });
break;
default:
Object.assign(options, { lines: 8, length: 4, width: 3, radius: 5 });
}
new Spinner(options).spin(this.element);
}
}

View File

@ -0,0 +1,61 @@
import Component, { ComponentAttrs } from '../Component';
import classList from '../utils/classList';
export interface LoadingIndicatorAttrs extends ComponentAttrs {
/**
* Custom classes fro the loading indicator's container.
*/
className?: string;
/**
* Custom classes for the loading indicator's container.
*/
containerClassName?: string;
/**
* Optional size to specify for the loading indicator.
*/
size?: 'large' | 'medium' | 'small';
/**
* Optional attributes to apply to the loading indicator's container.
*/
containerAttrs?: Partial<ComponentAttrs>;
}
/**
* The `LoadingIndicator` component displays a simple CSS-based loading spinner.
*
* To set a custom color, use the CSS `color` property.
*
* To increase spacing around the spinner, use the CSS `height` property on the
* spinner's **container**.
*
* To apply a custom size to the loading indicator, set the `--size` and
* `--thickness` custom properties on the loading indicator itself.
*
* If you really want to change how this looks as part of your custom theme,
* you can override the `border-radius` and `border` then set either a
* background image, or use `content: "\<glyph>"` (e.g. `content: "\f1ce"`)
* and `font-family: 'Font Awesome 5 Free'` to set an FA icon if you'd rather.
*
* ### Attrs
*
* - `containerClassName` Class name(s) to apply to the indicator's parent
* - `className` Class name(s) to apply to the indicator itself
* - `size` Size of the loading indicator
* - `containerAttrs` Optional attrs to be applied to the container DOM element
*
* All other attrs will be assigned as attributes on the DOM element.
*/
export default class LoadingIndicator extends Component<LoadingIndicatorAttrs> {
view() {
const { size, ...attrs } = this.attrs;
attrs.className = classList({ LoadingIndicator: true, [attrs.className || '']: true });
attrs.containerClassName = classList({ 'LoadingIndicator-container': true, [attrs.containerClassName || '']: true });
return (
<div {...attrs.containerAttrs} data-size={size} className={attrs.containerClassName}>
<div {...attrs}></div>
</div>
);
}
}

View File

@ -15,13 +15,9 @@
float: left;
margin-left: -65px;
margin-top: -4px;
.LoadingIndicator {
display: inline-block;
margin-left: 20px;
}
}
}
.Checkbox--switch .Checkbox-display {
width: 50px;
height: 28px;
@ -31,8 +27,28 @@
background: @control-bg;
.transition(background-color 0.2s);
.LoadingIndicator {
--size: 22px !important;
&-container {
height: 22px;
}
}
.on& {
background: #58a400;
.LoadingIndicator-container {
// Show loading indicator over the switch button
justify-content: flex-end;
}
}
.off& {
.LoadingIndicator-container {
// Show loading indicator over the switch button
justify-content: flex-start;
}
}
&:before {

View File

@ -2,13 +2,58 @@
// Loading Indicators
.LoadingIndicator {
position: relative;
color: @muted-color;
@spin-time: 750ms;
--size: 24px;
--thickness: 2px;
&-container[data-size="large"] & {
--size: 32px;
--thickness: 3px;
}
&-container[data-size="tiny"] & {
--size: 18px;
}
// Use the value of `color` to maintain backwards compatibility
border-color: currentColor;
border-width: var(--thickness);
border-style: solid;
border-top-color: transparent;
border-radius: 50%;
width: var(--size);
height: var(--size);
animation: spin @spin-time linear infinite;
// <div> container around the spinner
// Used for positioning
&-container {
color: @muted-color;
// Center vertically and horizontally
// Allows people to set `height` and it'll stay centered within the new height
display: flex;
align-items: center;
justify-content: center;
&--block {
height: 100px;
}
&--inline {
display: inline-block;
}
}
}
.LoadingIndicator--inline {
display: inline-block;
width: 25px;
}
.LoadingIndicator--block {
height: 100px;
@keyframes spin {
from {
transform: rotate(0);
}
to {
transform: rotate(1turn);
}
}

View File

@ -2,7 +2,7 @@
text-align: center;
margin-top: 10px;
.LoadingIndicator {
.LoadingIndicator-container {
height: 46px;
}
}

View File

@ -10,9 +10,10 @@
.DiscussionList-loadMore {
text-align: center;
margin-top: 10px;
}
.DiscussionList-loadMore .LoadingIndicator {
height: 46px;
.LoadingIndicator-container {
height: 46px;
}
}
@media @phone {