1
- import React , { forwardRef , useRef , useState , useEffect } from 'react' ;
2
- import propTypes from 'prop-types' ;
3
-
1
+ import React , {
2
+ forwardRef ,
3
+ useCallback ,
4
+ useEffect ,
5
+ useRef ,
6
+ useState
7
+ } from 'react' ;
4
8
import styled , { css } from 'styled-components' ;
5
9
6
- import { StyledCutout } from '../Cutout/Cutout' ;
7
10
import { blockSizes } from '../common/system' ;
11
+ import { StyledCutout } from '../Cutout/Cutout' ;
12
+ import { CommonStyledProps } from '../types' ;
13
+
14
+ type ProgressProps = {
15
+ hideValue ?: boolean ;
16
+ shadow ?: boolean ;
17
+ value ?: number ;
18
+ variant ?: 'default' | 'tile' ;
19
+ } & React . HTMLAttributes < HTMLDivElement > &
20
+ CommonStyledProps ;
8
21
9
22
const Wrapper = styled . div `
10
23
display: inline-block;
@@ -42,7 +55,7 @@ const WhiteBar = styled.div`
42
55
color: ${ ( { theme } ) => theme . materialText } ;
43
56
` ;
44
57
45
- const BlueBar = styled . div `
58
+ const BlueBar = styled . div < Required < Pick < ProgressProps , 'value' > > > `
46
59
position: absolute;
47
60
top: 2px;
48
61
left: 2px;
@@ -79,53 +92,45 @@ const Tile = styled.span`
79
92
border-style: solid;
80
93
` ;
81
94
82
- const Progress = forwardRef ( function Progress ( props , ref ) {
83
- const { value, variant, shadow, hideValue, ...otherProps } = props ;
95
+ const Progress = forwardRef < HTMLDivElement , ProgressProps > ( function Progress (
96
+ {
97
+ hideValue = false ,
98
+ shadow = true ,
99
+ value = 0 ,
100
+ variant = 'default' ,
101
+ ...otherProps
102
+ } ,
103
+ ref
104
+ ) {
84
105
const displayValue = hideValue ? null : `${ value } %` ;
85
106
86
- const progressProps = { } ;
87
- if ( value !== undefined ) {
88
- progressProps [ 'aria-valuenow' ] = Math . round ( value ) ;
89
- }
90
-
91
- const tilesWrapperRef = useRef ( ) ;
92
- const savedCallback = useRef ( ) ;
93
- const [ tilesNumber , setTilesNumber ] = useState ( 0 ) ;
107
+ const tilesWrapperRef = useRef < HTMLDivElement | null > ( null ) ;
108
+ const [ tiles , setTiles ] = useState ( [ ] ) ;
94
109
95
110
// TODO debounce this function
96
- function updateTilesNumber ( ) {
97
- if ( tilesWrapperRef . current ) {
98
- const progressWidth =
99
- tilesWrapperRef . current . getBoundingClientRect ( ) . width ;
100
- const newTilesNumber = Math . round (
101
- ( ( value / 100 ) * progressWidth ) / tileWidth
102
- ) ;
103
- setTilesNumber ( newTilesNumber ) ;
111
+ const updateTilesNumber = useCallback ( ( ) => {
112
+ if ( ! tilesWrapperRef . current ) {
113
+ return ;
104
114
}
105
- }
106
- useEffect ( ( ) => {
107
- savedCallback . current = updateTilesNumber ;
108
- } ) ;
115
+ const progressWidth = tilesWrapperRef . current . getBoundingClientRect ( ) . width ;
116
+ const newTilesNumber = Math . round (
117
+ ( ( value / 100 ) * progressWidth ) / tileWidth
118
+ ) ;
119
+ setTiles ( Array . from ( { length : newTilesNumber } ) ) ;
120
+ } , [ value ] ) ;
121
+
109
122
useEffect ( ( ) => {
110
- function update ( ) {
111
- savedCallback . current ( ) ;
112
- }
123
+ updateTilesNumber ( ) ;
113
124
114
- // then listen on window resize to recalculate number of tiles
115
- window . addEventListener ( 'resize' , update ) ;
116
- return ( ) => window . removeEventListener ( 'resize' , update ) ;
117
- } , [ ] ) ;
125
+ window . addEventListener ( 'resize' , updateTilesNumber ) ;
126
+ return ( ) => window . removeEventListener ( 'resize' , updateTilesNumber ) ;
127
+ } , [ updateTilesNumber ] ) ;
118
128
119
- // recalculate number of tiles when value changes
120
- useEffect ( ( ) => {
121
- savedCallback . current ( ) ;
122
- } , [ value ] ) ;
123
129
return (
124
130
< Wrapper
125
- // TODO what to do with ref from forwardRef ?
131
+ aria-valuenow = { value !== undefined ? Math . round ( value ) : undefined }
126
132
ref = { ref }
127
133
role = 'progressbar'
128
- { ...progressProps }
129
134
{ ...otherProps }
130
135
>
131
136
< ProgressCutout shadow = { shadow } >
@@ -138,30 +143,14 @@ const Progress = forwardRef(function Progress(props, ref) {
138
143
</ >
139
144
) : (
140
145
< TilesWrapper ref = { tilesWrapperRef } data-testid = 'tileProgress' >
141
- { Array ( tilesNumber )
142
- . fill ( null )
143
- . map ( ( _ , index ) => (
144
- < Tile key = { index } />
145
- ) ) }
146
+ { tiles . map ( ( _ , index ) => (
147
+ < Tile key = { index } />
148
+ ) ) }
146
149
</ TilesWrapper >
147
150
) }
148
151
</ ProgressCutout >
149
152
</ Wrapper >
150
153
) ;
151
154
} ) ;
152
155
153
- Progress . defaultProps = {
154
- value : 0 ,
155
- shadow : true ,
156
- variant : 'default' ,
157
- hideValue : false
158
- } ;
159
-
160
- Progress . propTypes = {
161
- value : propTypes . number ,
162
- shadow : propTypes . bool ,
163
- variant : propTypes . oneOf ( [ 'default' , 'tile' ] ) ,
164
- hideValue : propTypes . bool
165
- } ;
166
-
167
- export default Progress ;
156
+ export { Progress , ProgressProps } ;
0 commit comments