Skip to content

Commit a48103e

Browse files
authored
Merge pull request #465 from facultyai/jason/spinner
Keep children in layout when spinner is loading. Tests updated
2 parents e2f9fc8 + 148d61f commit a48103e

File tree

2 files changed

+84
-39
lines changed

2 files changed

+84
-39
lines changed

src/components/Spinner.js

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,6 @@ const Spinner = props => {
4141

4242
const isSpinnerColor = spinnerColors.has(color);
4343

44-
// this spacing is consistent with the behaviour of dcc.Loading
45-
// it can be overridden with spinnerStyle
46-
const defaultSpinnerStyle = children
47-
? {display: 'block', margin: '1rem auto'}
48-
: {};
49-
const spinnerStyle = {...defaultSpinnerStyle, ...spinner_style};
50-
5144
const fullscreenStyle = {
5245
position: 'fixed',
5346
width: '100vw',
@@ -59,35 +52,70 @@ const Spinner = props => {
5952
justifyContent: 'center',
6053
alignItems: 'center',
6154
zIndex: 99,
55+
visibility: 'visible',
6256
...fullscreen_style
6357
};
6458

65-
if (!children || (loading_state && loading_state.is_loading)) {
66-
if (fullscreen) {
67-
return (
68-
<div className={fullscreenClassName} style={fullscreenStyle}>
69-
<RSSpinner
70-
color={isSpinnerColor ? color : null}
71-
style={{color: !isSpinnerColor && color, ...spinnerStyle}}
72-
className={spinnerClassName}
73-
{...omit(['setProps'], otherProps)}
74-
/>
75-
</div>
76-
);
77-
}
59+
const SpinnerDiv = style => (
60+
<RSSpinner
61+
color={isSpinnerColor ? color : null}
62+
style={{color: !isSpinnerColor && color, ...style}}
63+
className={spinnerClassName}
64+
{...omit(['setProps'], otherProps)}
65+
/>
66+
);
67+
// Defaulted styles above to the situation where spinner has no children
68+
// now include properties if spinner has children
69+
if (children) {
70+
// include covering style additions
71+
const coveringStyle = {
72+
visibility: 'visible',
73+
position: 'absolute',
74+
top: 0,
75+
height: '100%',
76+
width: '100%',
77+
display: 'flex',
78+
justifyContent: 'center',
79+
alignItems: 'center'
80+
};
81+
82+
const hiddenStyle = {
83+
visibility: 'hidden',
84+
position: 'relative'
85+
};
86+
87+
const spinnerStyle = {
88+
display: 'block',
89+
margin: '1rem auto',
90+
...spinner_style
91+
};
92+
93+
const showSpinner = loading_state && loading_state.is_loading;
94+
7895
return (
79-
<RSSpinner
80-
color={isSpinnerColor ? color : null}
81-
style={{color: !isSpinnerColor && color, ...spinnerStyle}}
82-
className={spinnerClassName}
83-
{...omit(['setProps'], otherProps)}
84-
/>
96+
<div style={showSpinner ? hiddenStyle : {}}>
97+
{children}
98+
{showSpinner && (
99+
<div
100+
style={fullscreen ? fullscreenStyle : coveringStyle}
101+
className={fullscreen && fullscreenClassName}
102+
>
103+
<SpinnerDiv style={spinnerStyle} />
104+
</div>
105+
)}
106+
</div>
85107
);
86108
}
87-
if (type(children) !== 'Object' || type(children) !== 'Function') {
88-
return <Fragment>{children}</Fragment>;
109+
110+
if (fullscreen) {
111+
return (
112+
<div className={fullscreenClassName} style={fullscreenStyle}>
113+
<SpinnerDiv style={spinner_style} />
114+
</div>
115+
);
89116
}
90-
return children;
117+
118+
return <SpinnerDiv style={spinner_style} />;
91119
};
92120

93121
Spinner._dashprivate_isLoadingComponent = true;

src/components/__tests__/Spinner.test.js

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,53 @@ describe('Spinner', () => {
1212
});
1313

1414
test("renders its content if object isn't loading", () => {
15-
const {container: spinner, rerender} = render(<Spinner>Some spinner content</Spinner>);
15+
const {container: All, rerender} = render(
16+
<Spinner>Some spinner content</Spinner>
17+
);
1618

17-
expect(spinner).toHaveTextContent('Some spinner content');
19+
expect(All).toHaveTextContent('Some spinner content');
1820

1921
rerender(
2022
<Spinner loading_state={{is_loading: true}}>Some spinner content</Spinner>
2123
);
2224

23-
expect(spinner).not.toHaveTextContent('Some spinner content');
25+
const overAll = All.firstChild;
26+
const spinner = overAll.lastChild;
27+
28+
expect(overAll).toHaveTextContent('Some spinner content');
2429
expect(spinner.firstChild).toHaveClass('spinner-border');
2530
});
2631

2732
test('applies additional CSS classes when props are set', () => {
2833
// grow spinner
29-
const {container: {firstChild: spinnerGrow}} = render(<Spinner type="grow" />);
34+
const {
35+
container: {firstChild: spinner}
36+
} = render(<Spinner type="grow" />);
3037

31-
expect(spinnerGrow).toHaveClass('spinner-grow');
38+
expect(spinner).toHaveClass('spinner-grow');
3239

3340
// spinner sizes
34-
const {container: {firstChild: spinnerSm}} = render(<Spinner size="sm" />);
35-
const {container: {firstChild: spinnerLg}} = render(<Spinner size="lg" />);
41+
const {
42+
container: {firstChild: spinnerSm}
43+
} = render(<Spinner size="sm" />);
44+
const {
45+
container: {firstChild: spinnerLg}
46+
} = render(<Spinner size="lg" />);
3647

3748
expect(spinnerSm).toHaveClass('spinner-border-sm');
3849
expect(spinnerLg).toHaveClass('spinner-border-lg');
3950
});
4051

4152
test('applies contextual colors with "color" prop', () => {
42-
const {container: {firstChild: spinnerPrimary}} = render(<Spinner color="primary" />);
43-
const {container: {firstChild: spinnerSuccess}} = render(<Spinner color="success" />);
44-
const {container: {firstChild: spinnerDark}} = render(<Spinner color="dark" />);
53+
const {
54+
container: {firstChild: spinnerPrimary}
55+
} = render(<Spinner color="primary" />);
56+
const {
57+
container: {firstChild: spinnerSuccess}
58+
} = render(<Spinner color="success" />);
59+
const {
60+
container: {firstChild: spinnerDark}
61+
} = render(<Spinner color="dark" />);
4562

4663
expect(spinnerPrimary).toHaveClass('text-primary');
4764
expect(spinnerSuccess).toHaveClass('text-success');

0 commit comments

Comments
 (0)