Skip to content

Commit

Permalink
EuiDualRange component (#1485)
Browse files Browse the repository at this point in the history
* WIP: range component break down; dualRange inital

* WIP: dual range docs examples

* WIP: propTypes; type def updates; baseline keyboard nav

* WIP: hasFocus for range highlight

* WIP: better rangeSlider ref access

* WIP: sass refactor using component boundaries

* update euiRange tests; create euiDualRange tests

* move range examples out of formControl; clean up

* remove thumb focus when disabled

* update docs to share intro

* default showRange to true for EuiDualRange; prop clean up

* class-based focus style when input is not focusable

* size input based on max number of characters via digits prop

* pass aria attrs through to focusable, changeable elements

* number service: isWithinRange

* account for invalid states; pass isValid to parent via onChange

* number service tests, scss whitespace clean up, onChange fn signature docs

* allow for empty string input value to prevent constant 0

* #1485 euiDualRange changelog update

* logic to always enable a valid state during thumb interactions

* comments for thumb positioning logic

* handle keyboard value stepping better; remove pseudo value from dual input

* better thumb swap logic; docs notice about value retrieval

* ts fixes; isWithinRange simplification

* min and max 0-length check

* rangeClasses -> sliderClasses

Name change suggestion from @cchaos

Co-Authored-By: thompsongl <thompsongl@users.noreply.github.com>

* move all components to individual files
  • Loading branch information
thompsongl authored Feb 6, 2019
1 parent 9faf2b4 commit d491d31
Show file tree
Hide file tree
Showing 45 changed files with 2,241 additions and 757 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- Created `EuiDualRange` using components from modularized, refactored `EuiRange`. New util service `isWithinRange` is the first in the number category. ([#1485](https://github.com/elastic/eui/pull/1485))

**Bug fixes**

- Fixed `EuiSearchBar.Query` match_all query string must be `*` ([#1521](https://github.com/elastic/eui/pull/1521))
Expand All @@ -26,13 +28,14 @@
## [`6.8.0`](https://github.com/elastic/eui/tree/v6.8.0)

- Changed `flex-basis` value on `EuiPageBody` for better cross-browser support ([#1497](https://github.com/elastic/eui/pull/1497))
- Converted a number of components to support text localization ([#1485](https://github.com/elastic/eui/pull/1485))
- Converted a number of components to support text localization ([#1450](https://github.com/elastic/eui/pull/1450))
- Added a seconds option to the refresh interval selection in `EuiSuperDatePicker` ([#1503](https://github.com/elastic/eui/pull/1503))
- Changed to conditionally render `EuiModalBody` if `EuiConfirmModal` has no `children` ([#1505](https://github.com/elastic/eui/pull/1505))
- Changed to conditionally render `EuiModalBody` if `EuiConfirmModal` has no `children` ([#1500](https://github.com/elastic/eui/pull/1500))


**Bug fixes**

- Remove `font-features` setting on `@euiFont` mixin to prevent breaks in ACE editor ([#1497](https://github.com/elastic/eui/pull/1497))
- Remove `font-features` setting on `@euiFont` mixin to prevent breaks in ACE editor ([#1505](https://github.com/elastic/eui/pull/1505))

## [`6.7.4`](https://github.com/elastic/eui/tree/v6.7.4)

Expand Down
4 changes: 4 additions & 0 deletions src-docs/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ import { PortalExample }
import { ProgressExample }
from './views/progress/progress_example';

import { RangeControlExample }
from './views/range/range_example';

import { ResponsiveExample }
from './views/responsive/responsive_example';

Expand Down Expand Up @@ -400,6 +403,7 @@ const navigation = [{
DatePickerExample,
ExpressionExample,
FilterGroupExample,
RangeControlExample,
SearchBarExample,
].map(example => createExample(example)),
},
Expand Down
35 changes: 0 additions & 35 deletions src-docs/src/views/form_controls/form_controls_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
EuiLink,
EuiRadio,
EuiRadioGroup,
EuiRange,
EuiSelect,
EuiSwitch,
EuiTextArea,
Expand Down Expand Up @@ -75,10 +74,6 @@ import RadioGroup from './radio_group';
const radioGroupSource = require('!!raw-loader!./radio_group');
const radioGroupHtml = renderToHtml(RadioGroup);

import RangeExample from './range';
const rangeSource = require('!!raw-loader!./range');
const rangeHtml = renderToHtml(RangeExample);

import Switch from './switch';
const switchSource = require('!!raw-loader!./switch');
const switchHtml = renderToHtml(Switch);
Expand Down Expand Up @@ -250,36 +245,6 @@ export const FormControlsExample = {
EuiRadioGroup,
},
demo: <RadioGroup />,
}, {
title: 'Range',
text: (
<Fragment>
<EuiCallOut color="warning" title="Understanding precision">
<p>
The base slider should only be used
when <strong>the precise value is not considered important</strong>. If
the precise value does matter, add the <code>showInput</code> prop or use
a <code>EuiFieldNumber</code> instead.
</p>
</EuiCallOut>
<br/>
<p>
While currently considered optional, the <code>showLabels</code> property should
be added to explicitly state the range to the user.
</p>
</Fragment>
),
source: [{
type: GuideSectionTypes.JS,
code: rangeSource,
}, {
type: GuideSectionTypes.HTML,
code: rangeHtml,
}],
props: {
EuiRange,
},
demo: <RangeExample />,
}, {
title: 'Switch',
source: [{
Expand Down
136 changes: 136 additions & 0 deletions src-docs/src/views/range/dual_range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React, {
Component,
Fragment,
} from 'react';

import {
EuiDualRange,
EuiSpacer,
EuiFormHelpText,
} from '../../../../src/components';

import makeId from '../../../../src/components/form/form_row/make_id';

export default class extends Component {
constructor(props) {
super(props);

this.levels = [
{
min: 0,
max: 600,
color: 'danger'
},
{
min: 600,
max: 2000,
color: 'success'
}
];

this.state = {
value: [120, 480]
};
}

onChange = (value) => {
this.setState({
value
});
};

render() {
return (
<Fragment>

<EuiDualRange
id={makeId()}
min={0}
max={2000}
value={this.state.value}
onChange={this.onChange}
aria-label="Use aria labels when no actual label is in use"
showLabels
name="dualRange"
/>

<EuiSpacer size="xl" />

<EuiDualRange
id={makeId()}
min={0}
max={2000}
value={this.state.value}
onChange={this.onChange}
disabled
aria-label="Use aria labels when no actual label is in use"
showLabels
/>

<EuiSpacer size="xl" />

<EuiDualRange
id={makeId()}
min={0}
max={2000}
value={this.state.value}
onChange={this.onChange}
aria-label="Use aria labels when no actual label is in use"
showLabels
showInput
showRange
/>

<EuiSpacer size="xl" />

<EuiDualRange
id={makeId()}
min={0}
max={2000}
step={50}
value={this.state.value}
onChange={this.onChange}
aria-label="Use aria labels when no actual label is in use"
aria-describedby="levelsHelp"
showLabels
showInput
compressed
levels={this.levels}
/>
<EuiFormHelpText id="levelsHelp">Recommended levels are 600 and above.</EuiFormHelpText>

<EuiSpacer size="xl" />

<EuiDualRange
id={makeId()}
min={0}
max={2000}
step={50}
value={this.state.value}
onChange={this.onChange}
aria-label="Use aria labels when no actual label is in use"
showTicks
showRange
tickInterval={300}
/>

<EuiSpacer size="xl" />

<EuiDualRange
id={makeId()}
min={0}
max={2000}
step={50}
value={this.state.value}
onChange={this.onChange}
aria-label="Use aria labels when no actual label is in use"
aria-describedby="levelsHelp"
showTicks
showInput
tickInterval={500}
levels={this.levels}
/>
</Fragment>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default class extends Component {
];

this.state = {
value: '120',
value: '120'
};
}

Expand Down
94 changes: 94 additions & 0 deletions src-docs/src/views/range/range_example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, { Fragment } from 'react';

import { renderToHtml } from '../../services';

import {
GuideSectionTypes,
} from '../../components';

import {
EuiCallOut,
EuiDualRange,
EuiRange,
EuiSpacer
} from '../../../../src/components';

import DualRangeExample from './dual_range';
const dualRangeSource = require('!!raw-loader!./dual_range');
const dualRangeHtml = renderToHtml(DualRangeExample);

import RangeExample from './range';
const rangeSource = require('!!raw-loader!./range');
const rangeHtml = renderToHtml(RangeExample);

export const RangeControlExample = {
title: 'Range',
intro: (
<Fragment>
<EuiCallOut color="warning" title="Understanding precision">
<p>
Range sliders should only be used
when <strong>the precise value is not considered important</strong>. If
the precise value does matter, add the <code>showInput</code> prop or use
a <code>EuiFieldNumber</code> instead.
</p>
<p>
While currently considered optional, the <code>showLabels</code> property should
be added to explicitly state the range to the user.
</p>
</EuiCallOut>
<EuiSpacer size="l" />
</Fragment>
),
sections: [
{
title: 'Range',
source: [{
type: GuideSectionTypes.JS,
code: rangeSource,
}, {
type: GuideSectionTypes.HTML,
code: rangeHtml,
}],
props: {
EuiRange,
},
demo: <RangeExample />,
},
{
title: 'DualRange',
text: (
<Fragment>
<EuiCallOut color="warning" title="Retrieving field values">
<p>
Two-value <code>input[type=range]</code> elements are not part of the HTML5 specification.
Because of this support gap, <code>EuiDualRange</code> cannot expose a native <code>value</code> property
for native <code>form</code> to consumption.
<strong>
The React <code>onChange</code> prop is the recommended method
for retrieving the upper and lower values.
</strong>
</p>
<p>
<code>EuiDualRange</code> does use native <code>input</code>s to help validate step values
and range limits. These may be used as <code>form</code> values when <code>showInput</code> is in use.
The alternative is to store values in <code>input[type=hidden]</code>.
</p>
</EuiCallOut>
<EuiSpacer size="l" />
</Fragment>
),
source: [{
type: GuideSectionTypes.JS,
code: dualRangeSource,
}, {
type: GuideSectionTypes.HTML,
code: dualRangeHtml,
}],
props: {
EuiDualRange,
},
demo: <DualRangeExample />,
}
]
};
2 changes: 1 addition & 1 deletion src/components/form/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export {
EuiRadio,
EuiRadioGroup,
} from './radio';
export { EuiRange } from './range';
export { EuiDualRange, EuiRange } from './range';
export { EuiSelect } from './select';
export {
EuiSuperSelect,
Expand Down
Loading

0 comments on commit d491d31

Please sign in to comment.