-
Notifications
You must be signed in to change notification settings - Fork 843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EuiSuperSelect #921
EuiSuperSelect #921
Changes from 30 commits
0c6aa97
fde6cb0
4130ef0
26e1bf4
8d95237
a6e1737
cd66733
0297577
8007fab
80ae4c5
22581e5
c966c74
548e529
b254617
70163a3
87a22a3
85dfc4d
d7bd5b0
8eb1e8b
5596d70
36feea2
95e87e0
e8c3fa0
3d98cbc
1dd88f4
a001055
2a7f5da
70d08c3
5e86527
249fa1a
648f2a0
9884c1e
ab9bd72
a5b1d33
d927eef
724486a
f0e4f39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import React, { | ||
Component, | ||
Fragment, | ||
} from 'react'; | ||
|
||
import { | ||
EuiSuperSelect, | ||
EuiSpacer, | ||
} from '../../../../src/components'; | ||
|
||
export default class extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.options = [ | ||
{ | ||
value: 'option_one', | ||
inputDisplay: 'Option one', | ||
disabled: true, | ||
'data-test-subj': 'option one', | ||
}, | ||
{ | ||
value: 'option_two', | ||
inputDisplay: 'Option two', | ||
}, | ||
{ | ||
value: 'option_three', | ||
inputDisplay: 'Option three has a super long text to see if it will truncate or what', | ||
}, | ||
]; | ||
|
||
this.state = { | ||
value: this.options[1].value, | ||
}; | ||
} | ||
|
||
onChange = (value) => { | ||
this.setState({ | ||
value: value, | ||
}); | ||
}; | ||
|
||
render() { | ||
return ( | ||
<Fragment> | ||
<EuiSuperSelect | ||
options={this.options} | ||
valueOfSelected={this.state.value} | ||
onChange={this.onChange} | ||
/> | ||
|
||
<EuiSpacer size="m" /> | ||
|
||
<EuiSuperSelect | ||
options={this.options} | ||
valueOfSelected={this.state.value} | ||
onChange={this.onChange} | ||
disabled | ||
/> | ||
|
||
<EuiSpacer size="m" /> | ||
|
||
<EuiSuperSelect | ||
options={this.options} | ||
valueOfSelected={this.state.value} | ||
onChange={this.onChange} | ||
isLoading | ||
/> | ||
|
||
<EuiSpacer size="m" /> | ||
|
||
<EuiSuperSelect | ||
options={this.options} | ||
valueOfSelected={this.state.value} | ||
onChange={this.onChange} | ||
isLoading | ||
disabled | ||
/> | ||
|
||
<EuiSpacer size="m" /> | ||
|
||
<EuiSuperSelect | ||
options={this.options} | ||
valueOfSelected={this.state.value} | ||
onChange={this.onChange} | ||
compressed | ||
/> | ||
</Fragment> | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import React, { | ||
Component, | ||
} from 'react'; | ||
|
||
import { | ||
EuiSuperSelect, | ||
EuiHealth, | ||
} from '../../../../src/components'; | ||
|
||
export default class extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.options = [ | ||
{ | ||
value: 'warning', | ||
inputDisplay: ( | ||
<EuiHealth color="subdued" style={{ lineHeight: 'inherit' }}> | ||
Warning | ||
</EuiHealth> | ||
), | ||
'data-test-subj': 'option-warning', | ||
disabled: true, | ||
}, | ||
{ | ||
value: 'minor', | ||
inputDisplay: ( | ||
<EuiHealth color="warning" style={{ lineHeight: 'inherit' }}> | ||
Minor | ||
</EuiHealth> | ||
), | ||
'data-test-subj': 'option-minor', | ||
}, | ||
{ | ||
value: 'critical', | ||
inputDisplay: ( | ||
<EuiHealth color="danger" style={{ lineHeight: 'inherit' }}> | ||
Critical | ||
</EuiHealth> | ||
), | ||
'data-test-subj': 'option-critical', | ||
}, | ||
]; | ||
|
||
this.state = { | ||
value: this.options[1].value, | ||
}; | ||
} | ||
|
||
onChange = (value) => { | ||
this.setState({ | ||
value: value, | ||
}); | ||
}; | ||
|
||
render() { | ||
return ( | ||
<EuiSuperSelect | ||
options={this.options} | ||
valueOfSelected={this.state.value} | ||
onChange={this.onChange} | ||
/> | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import React, { | ||
Component, | ||
Fragment, | ||
} from 'react'; | ||
|
||
import { | ||
EuiSuperSelect, | ||
EuiSpacer, | ||
EuiText, | ||
} from '../../../../src/components'; | ||
|
||
export default class extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.options = [ | ||
{ | ||
value: 'option_one', | ||
inputDisplay: 'Option one', | ||
dropdownDisplay: ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of putting I'm thinking along these lines: const healthToColorMap = {
0: 'warning',
1: 'subdued',
2: 'danger',
};
const healthToNameMap = {
0: 'Warning',
1: 'Minor',
2: 'Critical',
};
export default class extends Component {
constructor(props) {
super(props);
this.options = [
{
value: 'option_one',
// You can put anything you want inside of data.
data: {
name: 'Option one',
description: 'Has a short description giving more detail to the option.',
health: 0,
},
},
{
value: 'option_two',
data: {
name: 'Option two',
description: 'Has a short description giving more detail to the option.',
health: 1,
},
},
{
value: 'option_three',
data: {
name: 'Option three',
description: 'Has a short description giving more detail to the option.',
health: 2,
},
},
];
this.state = {
value: this.options[1].value,
};
}
onChange = (value) => {
this.setState({
value: value,
});
};
renderOption = option => {
const { name, description, health } = option.data;
return (
<Fragment>
<strong>{name}</strong>
<EuiHealth color={healthToColorMap[health]} style={{ lineHeight: 'inherit' }}>
healthToNameMap[health]
</EuiHealth>
<EuiSpacer size="xs" />
<EuiText size="s" color="subdued">
<p className="euiTextColor--subdued">{description}</p>
</EuiText>
</Fragment>
);
};
renderSelectedOption = option => {
return option.data.name;
};
render() {
return (
<Fragment>
<EuiSuperSelect
options={this.options}
valueOfSelected={this.state.value}
onChange={this.onChange}
itemLayoutAlign="top"
renderOption={this.renderOption}
renderSelectedOption={this.renderSelectedOption}
hasDividers
aria-label="Use aria labels when no actual label is in use"
/>
</Fragment>
);
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's valuable to have render-purposeful show this in the select box and show this in the drop down values. However, I would agree that also allowing a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My worry with this option, is that each option is no longer customizable, unless you add a bunch of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, the flexibility is nice in the way its set up now. I see us switching things out more from item to item with this one than the combobox. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do we have an example use case where each option is completely different? Do you think this will be a common requirement? I think we should optimize for the common use case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As it is right now, no. But it can be altered down the road to support this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @cchaos though I was more thinking from the technical perspective, e.g. is there a challenge with decorating hundreds (or thousands) of options with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cjcenizal That screen looks like EuiFilterGroup, which has a current implementation within our table / search components (which you can see on those pages respectively). It even adds search once it gets beyond 10 items. Will that not cover what you need? I don't know about it's scaling abilities, but it's a 1-1 design against the screen you showed, so my guess is that's the component we'd update further. By design EuiSuperSelect should not have search in it and is really just a stylized select of choices. We have combo box and the filter group stuff for the pattern you describe. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @snide Good call! Yes that could work, but it needs to be broken out into its own component. Looks like the table example you shared has it baked into its interface via the If we were to break it out into its own component, then at first glance it looks like the only difference between it and EuiSuperSelect would be that one has search and the other doesn't. |
||
<Fragment> | ||
<strong>Option one</strong> | ||
<EuiSpacer size="xs" /> | ||
<EuiText size="s" color="subdued"> | ||
<p className="euiTextColor--subdued">Has a short description giving more detail to the option.</p> | ||
</EuiText> | ||
</Fragment> | ||
), | ||
}, | ||
{ | ||
value: 'option_two', | ||
inputDisplay: 'Option two', | ||
dropdownDisplay: ( | ||
<Fragment> | ||
<strong>Option two</strong> | ||
<EuiSpacer size="xs" /> | ||
<EuiText size="s" color="subdued"> | ||
<p className="euiTextColor--subdued">Has a short description giving more detail to the option.</p> | ||
</EuiText> | ||
</Fragment> | ||
), | ||
}, | ||
{ | ||
value: 'option_three', | ||
inputDisplay: 'Option three', | ||
dropdownDisplay: ( | ||
<Fragment> | ||
<strong>Option three</strong> | ||
<EuiSpacer size="xs" /> | ||
<EuiText size="s" color="subdued"> | ||
<p className="euiTextColor--subdued">Has a short description giving more detail to the option.</p> | ||
</EuiText> | ||
</Fragment> | ||
), | ||
}, | ||
]; | ||
|
||
this.state = { | ||
value: this.options[1].value, | ||
inputDisplay: this.options[1].inputDisplay, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like this isn't being consumed anywhere, so I think we can remove it? |
||
}; | ||
} | ||
|
||
onChange = (value) => { | ||
this.setState({ | ||
value: value, | ||
inputDisplay: this.options.inputDisplay, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then we can simplify this to: this.setState({ value }); |
||
}); | ||
}; | ||
|
||
render() { | ||
return ( | ||
<EuiSuperSelect | ||
options={this.options} | ||
valueOfSelected={this.state.value} | ||
onChange={this.onChange} | ||
itemLayoutAlign="top" | ||
hasDividers | ||
/> | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import React from 'react'; | ||
|
||
import { renderToHtml } from '../../services'; | ||
|
||
import { | ||
GuideSectionTypes, | ||
} from '../../components'; | ||
|
||
import { | ||
EuiCode, | ||
EuiSuperSelect, | ||
} from '../../../../src/components'; | ||
|
||
import SuperSelect from './super_select'; | ||
const superSelectSource = require('!!raw-loader!./super_select'); | ||
const superSelectHtml = renderToHtml(SuperSelect); | ||
|
||
import SuperSelectBasic from './super_select_basic'; | ||
const superSelectBasicSource = require('!!raw-loader!./super_select_basic'); | ||
const superSelectBasicHtml = renderToHtml(SuperSelectBasic); | ||
|
||
import SuperSelectComplex from './super_select_complex'; | ||
const superSelectComplexSource = require('!!raw-loader!./super_select_complex'); | ||
const superSelectComplexHtml = renderToHtml(SuperSelectComplex); | ||
|
||
export const SuperSelectExample = { | ||
title: 'SuperSelect', | ||
sections: [{ | ||
source: [{ | ||
type: GuideSectionTypes.JS, | ||
code: superSelectBasicSource, | ||
}, { | ||
type: GuideSectionTypes.HTML, | ||
code: superSelectBasicHtml, | ||
}], | ||
text: ( | ||
<div> | ||
<p> | ||
This is a simple replacement component for <EuiCode>EuiSelect</EuiCode> if you | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It'd be nice if over on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added. |
||
need more customization in either the display of the input or option. Simply pass | ||
an array of option objects: | ||
</p> | ||
<ul> | ||
<li><EuiCode>value</EuiCode>: for storing unique value of item, </li> | ||
<li><EuiCode>inputDisplay</EuiCode>: what shows inside the form input when selected, </li> | ||
<li><EuiCode>dropdownDisplay</EuiCode>: (optional) what shows for the item in the dropdown</li> | ||
</ul> | ||
<p> | ||
… and the component will create a select styled button | ||
that triggers a popover of selectable items. | ||
</p> | ||
</div> | ||
), | ||
props: { EuiSuperSelect }, | ||
demo: <SuperSelectBasic />, | ||
}, | ||
{ | ||
title: 'More complex', | ||
source: [{ | ||
type: GuideSectionTypes.JS, | ||
code: superSelectComplexSource, | ||
}, { | ||
type: GuideSectionTypes.HTML, | ||
code: superSelectComplexHtml, | ||
}], | ||
text: ( | ||
<p> | ||
Both <EuiCode>inputDisplay</EuiCode> and <EuiCode>dropdownDisplay</EuiCode> accept | ||
React nodes. Therefore you can pass some descriptions with each option to show | ||
in the dropdown. If your options will most likely be multi-line, add | ||
the <EuiCode>hasDividers</EuiCode> prop to show borders between options. | ||
</p> | ||
), | ||
props: { }, | ||
demo: <SuperSelectComplex />, | ||
}, | ||
{ | ||
title: 'States', | ||
source: [{ | ||
type: GuideSectionTypes.JS, | ||
code: superSelectSource, | ||
}, { | ||
type: GuideSectionTypes.HTML, | ||
code: superSelectHtml, | ||
}], | ||
text: ( | ||
<p> | ||
You can pass the same props as you normally would to <EuiCode>EuiSelect</EuiCode> like | ||
disabled, isLoading, compressed, etc… | ||
</p> | ||
), | ||
props: { EuiSuperSelect }, | ||
demo: <SuperSelect />, | ||
}], | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add an example of
disabled
options and the application of pass-through props?It looks like unexpected props aren't passed through.