diff --git a/src/components/selectable/selectable.test.tsx b/src/components/selectable/selectable.test.tsx index 57af21b7847..a1d6c33114b 100644 --- a/src/components/selectable/selectable.test.tsx +++ b/src/components/selectable/selectable.test.tsx @@ -376,7 +376,7 @@ describe('EuiSelectable', () => { }); describe('onChange', () => { - it('calls onChange with selected options array and click/keyboard event', () => { + it('calls onChange with selected options array, click/keyboard event, and the clicked option', () => { const onChange = jest.fn(); const component = mount( @@ -388,11 +388,19 @@ describe('EuiSelectable', () => { expect(onChange).toHaveBeenCalledTimes(1); expect(onChange.mock.calls[0][0][0].checked).toEqual('on'); expect(onChange.mock.calls[0][1].type).toEqual('click'); + expect(onChange.mock.calls[0][2]).toEqual({ + ...options[0], + checked: 'on', + }); component.simulate('keydown', { key: 'Enter', shiftKey: true }); expect(onChange).toHaveBeenCalledTimes(2); expect(onChange.mock.calls[1][0][0].checked).toEqual('on'); expect(onChange.mock.calls[1][1].type).toEqual('keydown'); + expect(onChange.mock.calls[1][2]).toEqual({ + ...options[0], + checked: 'on', + }); }); }); diff --git a/src/components/selectable/selectable.tsx b/src/components/selectable/selectable.tsx index b3ac542fb10..cd40838d23f 100644 --- a/src/components/selectable/selectable.tsx +++ b/src/components/selectable/selectable.tsx @@ -96,11 +96,13 @@ export type EuiSelectableProps = CommonProps & options: Array>; /** * Passes back the altered `options` array with selected options having `checked: 'on'`. - * Also passes back the React click/keyboard event as a second argument. + * Also passes back the React click/keyboard event as a second argument, + * and the option that triggered the onChange event as a third argument. */ onChange?: ( options: Array>, - event: EuiSelectableOnChangeEvent + event: EuiSelectableOnChangeEvent, + changedOption: EuiSelectableOption ) => void; /** * Passes back the current active option whenever the user changes the currently @@ -455,7 +457,8 @@ export class EuiSelectable extends Component< onOptionClick = ( options: Array>, - event: EuiSelectableOnChangeEvent + event: EuiSelectableOnChangeEvent, + clickedOption: EuiSelectableOption ) => { const { isPreFiltered, onChange } = this.props; const { searchValue } = this.state; @@ -468,7 +471,7 @@ export class EuiSelectable extends Component< this.setState({ visibleOptions }); if (onChange) { - onChange(options, event); + onChange(options, event, clickedOption); } }; diff --git a/src/components/selectable/selectable_list/selectable_list.tsx b/src/components/selectable/selectable_list/selectable_list.tsx index d09fb10792d..a0799637799 100644 --- a/src/components/selectable/selectable_list/selectable_list.tsx +++ b/src/components/selectable/selectable_list/selectable_list.tsx @@ -108,11 +108,13 @@ export type EuiSelectableListProps = EuiSelectableOptionsListProps & { */ searchValue: string; /** - * Returns the array of options with altered checked state + * Returns the array of options with altered checked state, the click/keyboard event, + * and the option that triggered the click/keyboard event */ onOptionClick: ( options: Array>, - event: EuiSelectableOnChangeEvent + event: EuiSelectableOnChangeEvent, + clickedOption: EuiSelectableOption ) => void; /** * Custom render for the label portion of the option; @@ -450,6 +452,7 @@ export class EuiSelectableList extends Component> { event: EuiSelectableOnChangeEvent ) => { const { onOptionClick, options, singleSelection } = this.props; + let changedOption = { ...addedOption }; const updatedOptions = options.map((option) => { // if singleSelection is enabled, uncheck any selected option(s) @@ -461,12 +464,13 @@ export class EuiSelectableList extends Component> { // if this is the now-selected option, check it if (option === addedOption) { updatedOption.checked = 'on'; + changedOption = updatedOption; } return updatedOption; }); - onOptionClick(updatedOptions, event); + onOptionClick(updatedOptions, event, changedOption); }; private onRemoveOption = ( @@ -474,18 +478,20 @@ export class EuiSelectableList extends Component> { event: EuiSelectableOnChangeEvent ) => { const { onOptionClick, singleSelection, options } = this.props; + let changedOption = { ...removedOption }; const updatedOptions = options.map((option) => { const updatedOption = { ...option }; if (option === removedOption && singleSelection !== 'always') { delete updatedOption.checked; + changedOption = updatedOption; } return updatedOption; }); - onOptionClick(updatedOptions, event); + onOptionClick(updatedOptions, event, changedOption); }; private onExcludeOption = ( @@ -493,18 +499,19 @@ export class EuiSelectableList extends Component> { event: EuiSelectableOnChangeEvent ) => { const { onOptionClick, options } = this.props; - excludedOption.checked = 'off'; + let changedOption = { ...excludedOption }; const updatedOptions = options.map((option) => { const updatedOption = { ...option }; if (option === excludedOption) { updatedOption.checked = 'off'; + changedOption = updatedOption; } return updatedOption; }); - onOptionClick(updatedOptions, event); + onOptionClick(updatedOptions, event, changedOption); }; } diff --git a/upcoming_changelogs/6487.md b/upcoming_changelogs/6487.md new file mode 100644 index 00000000000..a3c28ea8019 --- /dev/null +++ b/upcoming_changelogs/6487.md @@ -0,0 +1 @@ +- Added a third argument to `EuiSelectable`'s `onChange` callback. The single `option` object that triggered the `onChange` event is now also passed to consumers with its most recent `checked` state