@@ -10,15 +10,14 @@ import './react-select.scss';
10
10
*/
11
11
12
12
import NewSelect from '@data-driven-forms/common/src/select' ;
13
+ import { DropdownButton } from 'patternfly-react' ;
14
+ import fnToString from '@data-driven-forms/common/src/utils/fn-to-string' ;
15
+ import clsx from 'clsx' ;
13
16
import Option from './option' ;
14
17
import DropdownIndicator from './dropdown-indicator' ;
15
18
import ClearIndicator from './clear-indicator' ;
16
- import { DropdownButton , FormControl } from 'patternfly-react' ;
17
- import clsx from 'clsx' ;
18
19
import './react-select.scss' ;
19
20
20
- const fnToString = ( fn = '' ) => fn . toString ( ) . replace ( / \s + / g, ' ' ) ;
21
-
22
21
const ValueContainer = ( { children, ...props } ) => {
23
22
if ( props . isMulti ) {
24
23
return (
@@ -231,7 +230,7 @@ class SearchInput extends Component {
231
230
232
231
}
233
232
234
- const SelectTitle = ( { title, classNamePrefix, isClearable, value, onClear } ) => (
233
+ const SelectTitle = ( { title, classNamePrefix, isClearable, value, onClear, isFetching , isDisabled } ) => (
235
234
< Fragment >
236
235
< span key = "searchable-select-value-label" className = { `${ classNamePrefix } -value` } > { title } </ span >
237
236
{ isClearable && value && (
@@ -244,24 +243,81 @@ const SelectTitle = ({ title, classNamePrefix, isClearable, value, onClear }) =>
244
243
< i className = "fa fa-times" />
245
244
</ div >
246
245
) }
246
+ { ! isDisabled && isFetching && (
247
+ < i className = "ddorg__pf3-component-mapper__select__dropdown-indicator fa fa-circle-o-notch spin" />
248
+ ) }
249
+ { ! isDisabled && ! isFetching && (
250
+ < i className = "ddorg__pf3-component-mapper__select__dropdown-indicator fa fa-angle-down" />
251
+ ) }
247
252
</ Fragment >
248
253
) ;
249
254
250
- export class P3Select extends Component {
251
- state = {
255
+ export class P3Select extends Component { constructor ( props ) {
256
+ super ( props ) ;
257
+ this . state = {
258
+ isFetching : false ,
252
259
isOpen : false ,
253
- }
260
+ options : props . options || [ ] ,
261
+ } ;
262
+ }
254
263
handleToggleOpen = ( ) => this . setState ( ( { isOpen } ) => ( { isOpen : ! isOpen } ) )
255
264
256
- componentDidUpdate ( prevProps , prevState ) {
257
- //console.log('root update', prevState, this.state);
265
+ componentDidMount ( ) {
266
+ const { loadOptions } = this . props ;
267
+ if ( loadOptions ) {
268
+ return this . updateOptions ( ) ;
269
+ }
270
+ }
271
+
272
+ componentDidUpdate ( prevProps ) {
273
+ if ( ! isEqual ( this . props . options , prevProps . options ) ) {
274
+ if ( ! this . props . options . map ( ( { value } ) => value ) . includes ( this . props . input . value ) ) {
275
+ this . props . input . onChange ( undefined ) ;
276
+ }
277
+
278
+ this . setState ( { options : this . props . options } ) ;
279
+ }
280
+
281
+ if ( this . props . loadOptions && fnToString ( this . props . loadOptions ) !== fnToString ( prevProps . loadOptions ) ) {
282
+ return this . updateOptions ( ) ;
283
+ }
284
+ }
285
+
286
+ updateOptions = ( ) => {
287
+ const { loadOptions } = this . props ;
288
+
289
+ this . setState ( { isFetching : true } ) ;
290
+
291
+ return loadOptions ( )
292
+ . then ( ( data ) => {
293
+ if ( ! data . map ( ( { value } ) => value ) . includes ( this . props . input . value ) ) {
294
+ this . props . input . onChange ( undefined ) ;
295
+ }
296
+
297
+ return this . setState ( {
298
+ options : data ,
299
+ isFetching : false ,
300
+ } ) ;
301
+ } ) ;
258
302
}
259
303
260
304
shouldComponentUpdate ( nextProps , nextState ) {
261
305
if ( nextState . isOpen !== this . state . isOpen ) {
262
306
return true ;
263
307
}
264
308
309
+ if ( nextState . isFetching !== this . state . isFetching ) {
310
+ return true ;
311
+ }
312
+
313
+ if ( isEqual ( this . state . options , nextState . options ) ) {
314
+ return true ;
315
+ }
316
+
317
+ if ( this . props . loadOptions && fnToString ( this . props . loadOptions ) !== fnToString ( nextProps . loadOptions ) ) {
318
+ return true ;
319
+ }
320
+
265
321
if ( JSON . stringify ( nextProps ) !== JSON . stringify ( this . props ) ) {
266
322
return true ;
267
323
}
@@ -270,10 +326,10 @@ export class P3Select extends Component {
270
326
}
271
327
272
328
render ( ) {
273
- const { input, ...props } = this . props ;
274
- const { isOpen } = this . state ;
275
- const [ title , isPlaceholder ] = getDropdownText ( input . value , props . placeholder , props . options ) ;
329
+ const { input, loadOptions, options : _options , ...props } = this . props ;
330
+ const { isOpen, options, isFetching } = this . state ;
276
331
if ( props . isSearchable ) {
332
+ const [ title , isPlaceholder ] = getDropdownText ( input . value , props . placeholder , options ) ;
277
333
const searchableInput = {
278
334
...input ,
279
335
onChange : props . isMulti || props . multi
@@ -288,10 +344,12 @@ export class P3Select extends Component {
288
344
< DropdownButton
289
345
onToggle = { ( ) => this . handleToggleOpen ( ) }
290
346
disabled = { props . isDisabled }
291
- noCaret = { props . isDisabled }
347
+ noCaret
292
348
open = { isOpen }
293
349
id = { props . id || props . input . name }
294
350
title = { < SelectTitle
351
+ isDisabled = { props . isDisabled }
352
+ isFetching = { isFetching }
295
353
classNamePrefix = { this . props . classNamePrefix }
296
354
value = { input . value }
297
355
isClearable = { props . isClearable }
@@ -302,29 +360,31 @@ export class P3Select extends Component {
302
360
'is-empty' : isPlaceholder ,
303
361
} ) } >
304
362
{ isOpen &&
305
- < NewSelect
306
- input = { searchableInput }
307
- { ...props }
308
- className = { clsx ( props . classNamePrefix , {
309
- sercheable : props . isSearchable ,
310
- } ) }
311
- controlShouldRenderValue = { false }
312
- hideSelectedOptions = { false }
313
- isClearable = { false }
314
- tabSelectsValue = { false }
315
- menuIsOpen
316
- backspaceRemovesValue = { false }
317
- isMulti = { props . isMulti || props . multi }
318
- placeholder = "Search..."
319
- components = { {
320
- ClearIndicator,
321
- Option,
322
- DropdownIndicator : null ,
323
- IndicatorSeparator : null ,
324
- Placeholder : ( ) => null ,
325
- Input : ( { selectProps, cx, isHidden, isDisabled, innerRef, getStyles, ...props } ) =>
326
- < SearchInput id = { this . props . input . name } { ...props } /> ,
327
- } } /> }
363
+ < NewSelect
364
+ isFetching = { isFetching }
365
+ input = { searchableInput }
366
+ { ...props }
367
+ options = { options }
368
+ className = { clsx ( props . classNamePrefix , {
369
+ sercheable : props . isSearchable ,
370
+ } ) }
371
+ controlShouldRenderValue = { false }
372
+ hideSelectedOptions = { false }
373
+ isClearable = { false }
374
+ tabSelectsValue = { false }
375
+ menuIsOpen
376
+ backspaceRemovesValue = { false }
377
+ isMulti = { props . isMulti || props . multi }
378
+ placeholder = "Search..."
379
+ components = { {
380
+ ClearIndicator,
381
+ Option,
382
+ DropdownIndicator : null ,
383
+ IndicatorSeparator : null ,
384
+ Placeholder : ( ) => null ,
385
+ Input : ( { selectProps, cx, isHidden, isDisabled, innerRef, getStyles, ...props } ) =>
386
+ < SearchInput id = { this . props . input . name } { ...props } /> ,
387
+ } } /> }
328
388
</ DropdownButton >
329
389
</ div >
330
390
) ;
@@ -333,6 +393,8 @@ export class P3Select extends Component {
333
393
return (
334
394
< NewSelect
335
395
{ ...this . props }
396
+ isFetching = { isFetching }
397
+ options = { options }
336
398
input = { input }
337
399
className = { props . classNamePrefix }
338
400
components = { {
@@ -345,3 +407,7 @@ export class P3Select extends Component {
345
407
346
408
}
347
409
}
410
+
411
+ P3Select . defaultProps = {
412
+ placeholder : 'Search...' ,
413
+ } ;
0 commit comments