diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx index 09c59a22baf..f1cc467d8af 100644 --- a/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx +++ b/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx @@ -47,3 +47,7 @@ export const simple = () => ( export const withInitialValue = () => ( console.log(val)} /> ); + +export const withCustomValue = () => ( + console.log(val)} /> +); diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx index f6c3a80c6be..ba5db94db8f 100644 --- a/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx +++ b/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx @@ -29,18 +29,22 @@ const options = [ const flatOptions = [ { + singleLabel: 'Second', label: 'First / Second', value: ['1', '2'], }, { + singleLabel: 'Third', label: 'First / Third', value: ['1', '3'], }, { + singleLabel: 'Fourth', label: 'First / Fourth', value: ['1', '4'], }, { + singleLabel: 'FirstFirst', label: 'FirstFirst', value: ['5'], }, diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.tsx index 5e5ab5ee94e..ee904a19fa6 100644 --- a/packages/grafana-ui/src/components/Cascader/Cascader.tsx +++ b/packages/grafana-ui/src/components/Cascader/Cascader.tsx @@ -15,6 +15,7 @@ interface CascaderProps { onSelect(val: string): void; size?: FormInputSize; initialValue?: string; + allowCustomValue?: boolean; } interface CascaderState { @@ -64,6 +65,7 @@ export class Cascader extends React.PureComponent cpy.push(option); if (!option.items) { selectOptions.push({ + singleLabel: cpy[cpy.length - 1].label, label: cpy.map(o => o.label).join(this.props.separator || ' / '), value: cpy.map(o => o.value), }); @@ -84,10 +86,13 @@ export class Cascader extends React.PureComponent if (optionPath.indexOf(initValue) === optionPath.length - 1) { return { rcValue: optionPath, - activeLabel: option.label || '', + activeLabel: option.singleLabel || '', }; } } + if (this.props.allowCustomValue) { + return { rcValue: [], activeLabel: initValue }; + } return { rcValue: [], activeLabel: '' }; } @@ -95,7 +100,7 @@ export class Cascader extends React.PureComponent onChange = (value: string[], selectedOptions: CascaderOption[]) => { this.setState({ rcValue: value, - activeLabel: selectedOptions.map(o => o.label).join(this.props.separator || ' / '), + activeLabel: selectedOptions[selectedOptions.length - 1].label, }); this.props.onSelect(selectedOptions[selectedOptions.length - 1].value); @@ -103,12 +108,22 @@ export class Cascader extends React.PureComponent //For select onSelect = (obj: SelectableValue) => { + const valueArray = obj.value || []; this.setState({ - activeLabel: obj.label || '', - rcValue: obj.value || [], + activeLabel: obj.singleLabel || '', + rcValue: valueArray, isSearching: false, }); - this.props.onSelect(this.state.rcValue[this.state.rcValue.length - 1]); + this.props.onSelect(valueArray[valueArray.length - 1]); + }; + + onCreateOption = (value: string) => { + this.setState({ + activeLabel: value, + rcValue: [], + isSearching: false, + }); + this.props.onSelect(value); }; onClick = () => { @@ -138,47 +153,36 @@ export class Cascader extends React.PureComponent onInputKeyDown = (e: React.KeyboardEvent) => { if ( - e.key !== 'ArrowDown' && - e.key !== 'ArrowUp' && - e.key !== 'Enter' && - e.key !== 'ArrowLeft' && - e.key !== 'ArrowRight' + e.key === 'ArrowDown' || + e.key === 'ArrowUp' || + e.key === 'Enter' || + e.key === 'ArrowLeft' || + e.key === 'ArrowRight' ) { - this.setState({ - focusCascade: false, - isSearching: true, - }); - if (e.key === 'Backspace') { - const label = this.state.activeLabel || ''; - this.setState({ - activeLabel: label.slice(0, -1), - }); - } + return; } - }; - - onInputChange = (value: string) => { this.setState({ - activeLabel: value, + focusCascade: false, + isSearching: true, }); }; render() { - const { size } = this.props; + const { size, allowCustomValue } = this.props; const { focusCascade, isSearching, searchableOptions, rcValue, activeLabel } = this.state; return (
{isSearching ? (