@@ -10,15 +10,14 @@ import './react-select.scss';
1010 */
1111
1212import 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' ;
1316import Option from './option' ;
1417import DropdownIndicator from './dropdown-indicator' ;
1518import ClearIndicator from './clear-indicator' ;
16- import { DropdownButton , FormControl } from 'patternfly-react' ;
17- import clsx from 'clsx' ;
1819import './react-select.scss' ;
1920
20- const fnToString = ( fn = '' ) => fn . toString ( ) . replace ( / \s + / g, ' ' ) ;
21-
2221const ValueContainer = ( { children, ...props } ) => {
2322 if ( props . isMulti ) {
2423 return (
@@ -231,7 +230,7 @@ class SearchInput extends Component {
231230
232231}
233232
234- const SelectTitle = ( { title, classNamePrefix, isClearable, value, onClear } ) => (
233+ const SelectTitle = ( { title, classNamePrefix, isClearable, value, onClear, isFetching , isDisabled } ) => (
235234 < Fragment >
236235 < span key = "searchable-select-value-label" className = { `${ classNamePrefix } -value` } > { title } </ span >
237236 { isClearable && value && (
@@ -244,24 +243,81 @@ const SelectTitle = ({ title, classNamePrefix, isClearable, value, onClear }) =>
244243 < i className = "fa fa-times" />
245244 </ div >
246245 ) }
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+ ) }
247252 </ Fragment >
248253) ;
249254
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 ,
252259 isOpen : false ,
253- }
260+ options : props . options || [ ] ,
261+ } ;
262+ }
254263 handleToggleOpen = ( ) => this . setState ( ( { isOpen } ) => ( { isOpen : ! isOpen } ) )
255264
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+ } ) ;
258302 }
259303
260304 shouldComponentUpdate ( nextProps , nextState ) {
261305 if ( nextState . isOpen !== this . state . isOpen ) {
262306 return true ;
263307 }
264308
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+
265321 if ( JSON . stringify ( nextProps ) !== JSON . stringify ( this . props ) ) {
266322 return true ;
267323 }
@@ -270,10 +326,10 @@ export class P3Select extends Component {
270326 }
271327
272328 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 ;
276331 if ( props . isSearchable ) {
332+ const [ title , isPlaceholder ] = getDropdownText ( input . value , props . placeholder , options ) ;
277333 const searchableInput = {
278334 ...input ,
279335 onChange : props . isMulti || props . multi
@@ -288,10 +344,12 @@ export class P3Select extends Component {
288344 < DropdownButton
289345 onToggle = { ( ) => this . handleToggleOpen ( ) }
290346 disabled = { props . isDisabled }
291- noCaret = { props . isDisabled }
347+ noCaret
292348 open = { isOpen }
293349 id = { props . id || props . input . name }
294350 title = { < SelectTitle
351+ isDisabled = { props . isDisabled }
352+ isFetching = { isFetching }
295353 classNamePrefix = { this . props . classNamePrefix }
296354 value = { input . value }
297355 isClearable = { props . isClearable }
@@ -302,29 +360,31 @@ export class P3Select extends Component {
302360 'is-empty' : isPlaceholder ,
303361 } ) } >
304362 { 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+ } } /> }
328388 </ DropdownButton >
329389 </ div >
330390 ) ;
@@ -333,6 +393,8 @@ export class P3Select extends Component {
333393 return (
334394 < NewSelect
335395 { ...this . props }
396+ isFetching = { isFetching }
397+ options = { options }
336398 input = { input }
337399 className = { props . classNamePrefix }
338400 components = { {
@@ -345,3 +407,7 @@ export class P3Select extends Component {
345407
346408 }
347409}
410+
411+ P3Select . defaultProps = {
412+ placeholder : 'Search...' ,
413+ } ;
0 commit comments