@@ -82,52 +82,57 @@ export const Spinner: FC<SpinnerProps> = ({
82
82
unmountChildrenWhileLoading = false ,
83
83
...delegatedProps
84
84
} ) => {
85
- /**
86
- * @todo Figure out if this conditional logic can ever cause a component to
87
- * lose state when showSpinner flips from false to true while
88
- * unmountedWhileLoading is false. I would hope not, since the children prop
89
- * is the same in both cases, but I need to test this out
90
- */
85
+ // Conditional rendering logic is more convoluted than normal because we
86
+ // need to make sure that the children prop is always placed in the same JSX
87
+ // "slot" by default, no matter the value of `loading`. Even if the children
88
+ // prop value is exactly the same each time, the state will get wiped if the
89
+ // placement in the JSX output changes
91
90
const showSpinner = useShowSpinner ( loading , spinnerDelayMs ) ;
92
- if ( ! showSpinner ) {
93
- return children ;
94
- }
95
-
96
91
return (
97
92
< >
98
- < svg
99
- // Fill is the only prop that should be allowed to be
100
- // overridden; all other props must come after destructuring
101
- fill = "currentColor"
102
- { ...delegatedProps }
103
- viewBox = "0 0 24 24"
104
- xmlns = "http://www.w3.org/2000/svg"
105
- className = { cn ( className , spinnerVariants ( { size } ) ) }
106
- >
107
- < title > Loading…</ title >
108
- { leafIndices . map ( ( index ) => (
109
- < rect
110
- key = { index }
111
- x = "10.9"
112
- y = "2"
113
- width = "2"
114
- height = "5.5"
115
- rx = "1"
116
- style = { {
117
- ...animationSettings ,
118
- transform : `rotate(${ index * ( 360 / SPINNER_LEAF_COUNT ) } deg)` ,
119
- transformOrigin : "center" ,
120
- animationDelay : `${ - index * 0.1 } s` ,
121
- } }
122
- />
123
- ) ) }
124
- </ svg >
93
+ { showSpinner && (
94
+ < svg
95
+ // `fill` is the only prop that should be allowed to be
96
+ // overridden; all other props must come after destructuring
97
+ fill = "currentColor"
98
+ { ...delegatedProps }
99
+ viewBox = "0 0 24 24"
100
+ xmlns = "http://www.w3.org/2000/svg"
101
+ className = { cn ( className , spinnerVariants ( { size } ) ) }
102
+ >
103
+ < title > Loading…</ title >
104
+ { leafIndices . map ( ( index ) => (
105
+ < rect
106
+ key = { index }
107
+ x = "10.9"
108
+ y = "2"
109
+ width = "2"
110
+ height = "5.5"
111
+ rx = "1"
112
+ style = { {
113
+ ...animationSettings ,
114
+ transform : `rotate(${ index * ( 360 / SPINNER_LEAF_COUNT ) } deg)` ,
115
+ transformOrigin : "center" ,
116
+ animationDelay : `${ - index * 0.1 } s` ,
117
+ } }
118
+ />
119
+ ) ) }
120
+ </ svg >
121
+ ) }
125
122
126
- { ! unmountChildrenWhileLoading && (
127
- < div className = "sr-only" >
128
- This content is loading:
129
- { children }
130
- </ div >
123
+ { /*
124
+ * Invert the condition (showSpinner && unmountChildrenWhileLoading)
125
+ * (which is the only one that should result in fully-unmounted
126
+ * content), and then if we still get content, handle the other
127
+ * three cases of the boolean truth table more granularly
128
+ */ }
129
+ { ( ! showSpinner || ! unmountChildrenWhileLoading ) && (
130
+ < >
131
+ < span className = { showSpinner ? "sr-only" : "hidden" } >
132
+ This content is loading:{ " " }
133
+ </ span >
134
+ < span className = { showSpinner ? "sr-only" : "inline" } > { children } </ span >
135
+ </ >
131
136
) }
132
137
</ >
133
138
) ;
0 commit comments