diff --git a/CHANGELOG.md b/CHANGELOG.md index f26e8a6b796..5d68860295d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ - Update Elastic-Charts to version 13.0.0 and updated the theme object accordingly ([#2381](https://github.com/elastic/eui/pull/2381)) +**Bug fixes** + +- Fix `EuiSelectable` to accept programmatic updates to its `options` prop ([#2390](https://github.com/elastic/eui/pull/2390)) + ## [`14.4.0`](https://github.com/elastic/eui/tree/v14.4.0) - Migrate `EuiEmptyPrompt`and `EuiCard` to TS ([#2387](https://github.com/elastic/eui/pull/2387)) diff --git a/src-docs/src/views/selectable/selectable_search.tsx b/src-docs/src/views/selectable/selectable_search.tsx index 0d780caa96f..e94c755e1c3 100644 --- a/src-docs/src/views/selectable/selectable_search.tsx +++ b/src-docs/src/views/selectable/selectable_search.tsx @@ -1,5 +1,7 @@ import React, { Component, Fragment } from 'react'; +import { EuiButtonEmpty } from '../../../../src/components/button'; + import { EuiSelectable } from '../../../../src/components/selectable'; import { Option } from '../../../../src/components/selectable/types'; import { Options } from './data'; @@ -23,20 +25,33 @@ export default class extends Component<{}, { options: Option[] }> { const { options } = this.state; return ( - - {(list, search) => ( - - {search} - {list} - - )} - + + { + this.setState({ + options: Options.map(option => ({ + ...option, + checked: undefined, + })), + }); + }}> + Deselect all + + + {(list, search) => ( + + {search} + {list} + + )} + + ); } } diff --git a/src/components/selectable/selectable.tsx b/src/components/selectable/selectable.tsx index 7eb1d8354ca..86ba38155c9 100644 --- a/src/components/selectable/selectable.tsx +++ b/src/components/selectable/selectable.tsx @@ -148,6 +148,27 @@ export class EuiSelectable extends Component< }; } + static getDerivedStateFromProps( + nextProps: EuiSelectableProps, + prevState: EuiSelectableState + ) { + const { options } = nextProps; + const { activeOptionIndex, searchValue } = prevState; + + const matchingOptions = getMatchingOptions(options, searchValue); + + const stateUpdate = { visibleOptions: matchingOptions, activeOptionIndex }; + + if ( + activeOptionIndex != null && + activeOptionIndex >= matchingOptions.length + ) { + stateUpdate.activeOptionIndex = -1; + } + + return stateUpdate; + } + hasActiveOption = () => { return this.state.activeOptionIndex != null; };