diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9164b6b6cf2..01c46c5e0f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)
-No public interface changes since `1.0.1`.
+- Added more (mainly style) options to `EuiRange` ([#932](https://github.com/elastic/eui/pull/932))
## [`1.0.1`](https://github.com/elastic/eui/tree/v1.0.1)
diff --git a/src-docs/src/views/form_controls/form_controls_example.js b/src-docs/src/views/form_controls/form_controls_example.js
index 24cc55803fe..79cc694b7b1 100644
--- a/src-docs/src/views/form_controls/form_controls_example.js
+++ b/src-docs/src/views/form_controls/form_controls_example.js
@@ -69,9 +69,9 @@ import RadioGroup from './radio_group';
const radioGroupSource = require('!!raw-loader!./radio_group');
const radioGroupHtml = renderToHtml(RadioGroup);
-import Range from './range';
+import RangeExample from './range';
const rangeSource = require('!!raw-loader!./range');
-const rangeHtml = renderToHtml(Range);
+const rangeHtml = renderToHtml(RangeExample);
import Switch from './switch';
const switchSource = require('!!raw-loader!./switch');
@@ -238,6 +238,23 @@ export const FormControlsExample = {
demo: ,
}, {
title: 'Range',
+ text: (
+
+
+
+ The base slider should only be used
+ when the precise value is not considered important . If
+ the precise value does matter, add the showInput
prop or use
+ a EuiFieldNumber
instead.
+
+
+
+
+ While currently considered optional, the showLabels
property should
+ be added to explicitly state the range to the user.
+
+
+ ),
source: [{
type: GuideSectionTypes.JS,
code: rangeSource,
@@ -248,7 +265,7 @@ export const FormControlsExample = {
props: {
EuiRange,
},
- demo: ,
+ demo: ,
}, {
title: 'Switch',
source: [{
diff --git a/src-docs/src/views/form_controls/range.js b/src-docs/src/views/form_controls/range.js
index 89531edbdf3..d071610942a 100644
--- a/src-docs/src/views/form_controls/range.js
+++ b/src-docs/src/views/form_controls/range.js
@@ -6,6 +6,7 @@ import React, {
import {
EuiRange,
EuiSpacer,
+ EuiFormHelpText,
} from '../../../../src/components';
import makeId from '../../../../src/components/form/form_row/make_id';
@@ -14,6 +15,19 @@ 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',
};
@@ -35,9 +49,12 @@ export default class extends Component {
value={this.state.value}
onChange={this.onChange}
aria-label="Use aria labels when no actual label is in use"
+ showLabels
+ showValue
+ name="firstRange"
/>
-
+
+
+
+
+
+
+
+
+
+ Recommended levels are 600 and above.
+
+
+
+
+
+
+
+
);
diff --git a/src/components/button/_button.scss b/src/components/button/_button.scss
index 88d5b7f3be8..a75b3ffc179 100644
--- a/src/components/button/_button.scss
+++ b/src/components/button/_button.scss
@@ -77,7 +77,7 @@ $buttonTypes: (
text: $euiColorDarkShade, // Reserved for special use cases
);
-// Create button modifiders based upon the map.
+// Create button modifiers based upon the map.
@each $name, $color in $buttonTypes {
.euiButton--#{$name} {
diff --git a/src/components/form/range/__snapshots__/range.test.js.snap b/src/components/form/range/__snapshots__/range.test.js.snap
index 92524948419..e9539ebbf9b 100644
--- a/src/components/form/range/__snapshots__/range.test.js.snap
+++ b/src/components/form/range/__snapshots__/range.test.js.snap
@@ -1,24 +1,268 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EuiRange is rendered 1`] = `
-
+
+`;
+
+exports[`EuiRange props compressed should render 1`] = `
+
+`;
+
+exports[`EuiRange props extra input should render 1`] = `
+
`;
exports[`EuiRange props fullWidth should render 1`] = `
-
+
+`;
+
+exports[`EuiRange props labels should render 1`] = `
+
+
+ 1
+
+
+
+
+
+ 100
+
+
+`;
+
+exports[`EuiRange props levels should render 1`] = `
+
+`;
+
+exports[`EuiRange props range should render 1`] = `
+
+`;
+
+exports[`EuiRange props ticks should render 1`] = `
+
+`;
+
+exports[`EuiRange props value should render 1`] = `
+
`;
diff --git a/src/components/form/range/_index.scss b/src/components/form/range/_index.scss
index aac1bff53c5..7ef7e10548a 100644
--- a/src/components/form/range/_index.scss
+++ b/src/components/form/range/_index.scss
@@ -1,28 +1,3 @@
-$euiRangeTrackColor: $euiColorLightShade;
-
-$euiRangeThumbRadius: 50%;
-$euiRangeThumbHeight: $euiSize;
-$euiRangeThumbWidth: $euiSize;
-
-$euiRangeTrackWidth: 100%;
-$euiRangeTrackHeight: 2px;
-$euiRangeTrackBorderWidth: 0;
-$euiRangeTrackBorderColor: $euiColorLightShade;
-$euiRangeTrackRadius: $euiBorderRadius;
-
-@mixin track {
- cursor: pointer;
- height: $euiRangeTrackHeight;
- transition: all $euiAnimSpeedNormal ease-in;
- width: $euiRangeTrackWidth;
-}
-
-@mixin thumb {
- cursor: pointer;
- @include euiCustomControl($type: 'round');
- padding: 0;
- height: $euiRangeThumbHeight;
- width: $euiRangeThumbWidth;
-}
-
+@import 'variables';
+@import 'mixins';
@import 'range';
diff --git a/src/components/form/range/_mixins.scss b/src/components/form/range/_mixins.scss
new file mode 100644
index 00000000000..7e4da6b9afa
--- /dev/null
+++ b/src/components/form/range/_mixins.scss
@@ -0,0 +1,40 @@
+@mixin euiRange__trackSize {
+ height: $euiRangeTrackHeight;
+ transition: all $euiAnimSpeedNormal ease-in;
+ width: $euiRangeTrackWidth;
+}
+
+@mixin euiRange__track__perBrowser {
+ &::-webkit-slider-runnable-track { @content; }
+ &::-moz-range-track { @content; }
+ &::-ms-fill-lower { @content; }
+ &::-ms-fill-upper { @content; }
+}
+
+@mixin euiRange__thumb__perBrowser {
+ &::-webkit-slider-thumb { @content; }
+ &::-moz-range-thumb { @content; }
+ &::-ms-thumb { @content; }
+}
+
+//** DEPRECATED **//
+//** DEPRECATED **//
+//** DEPRECATED **//
+//** DEPRECATED **//
+
+@mixin track {
+ @warn "track() has been deprecated. Please use euiRange__trackSize() instead.";
+ cursor: pointer;
+ height: $euiRangeTrackHeight;
+ transition: all $euiAnimSpeedNormal ease-in;
+ width: $euiRangeTrackWidth;
+}
+
+@mixin thumb {
+ @warn "thumb() has been deprecated and styles moved to directly within the range selector.";
+ cursor: pointer;
+ @include euiCustomControl($type: 'round');
+ padding: 0;
+ height: $euiRangeThumbHeight;
+ width: $euiRangeThumbWidth;
+}
diff --git a/src/components/form/range/_range.scss b/src/components/form/range/_range.scss
index e4d0ff17318..7ff2b8c405a 100644
--- a/src/components/form/range/_range.scss
+++ b/src/components/form/range/_range.scss
@@ -1,3 +1,267 @@
+/*
+ * 1. There's no way to target the layout of the extra input, so we must
+ * use the descendant selector to allow the width to shrink.
+ * 2. Align extra input slightly better with slider labels, in an IE compliant way.
+ * 3. Adjust vertical alignment of input based on extras
+ */
+
+.euiRange__wrapper {
+ @include euiFormControlSize();
+ display: flex;
+ align-items: center;
+
+ &--fullWidth {
+ max-width: 100%;
+ }
+
+ &--disabled {
+ .euiRange__minLabel,
+ .euiRange__maxLabel,
+ .euiRange__inputWrapper {
+ opacity: .25;
+ }
+ }
+
+ > .euiFormControlLayout { /* 1 */
+ width: auto;
+ }
+}
+
+.euiRange__inputWrapper {
+ flex-grow: 1;
+ position: relative; // for positioning ticks/levels
+ align-self: flex-start; /* 3 */
+}
+
+.euiRange__minLabel,
+.euiRange__maxLabel {
+ font-size: $euiFontSizeXS;
+}
+
+.euiRange__minLabel {
+ margin-right: $euiSizeS;
+}
+
+.euiRange__maxLabel {
+ margin-left: $euiSizeS;
+}
+
+.euiRange__extraInput {
+ width: auto;
+ margin-left: $euiSize;
+ position: relative; /* 2 */
+ top: -2px; /* 2 */
+}
+
+.euiRange__tick {
+ overflow-x: hidden;
+ text-overflow: ellipsis;
+ font-size: $euiFontSizeXS;
+ position: relative;
+ padding-top: $euiSize;
+
+ &::before {
+ content: "";
+ @include size($euiSizeXS);
+ background-color: $euiColorDarkShade;
+ border-radius: 100%;
+ position: absolute;
+ top: 0;
+ left: calc(50% - #{($euiSizeXS/2)});
+ }
+
+ &:enabled:hover,
+ &:focus,
+ &--selected {
+ color: $euiColorPrimary;
+ }
+
+ &--selected {
+ font-weight: $euiFontWeightMedium;
+ }
+
+ &:disabled {
+ cursor: not-allowed;
+ }
+}
+
+.euiRange__levels {
+ display: flex;
+ justify-content: stretch;
+ z-index: $euiZLevel0;
+}
+
+[class*="euiRange__level--"] {
+ display: block;
+ height: 6px;
+ border-radius: 6px;
+ margin: 2px;
+}
+
+// Modifier naming and colors.
+$euiRange__levelColors: (
+ primary: $euiColorPrimary,
+ success: $euiColorSuccess,
+ warning: $euiColorWarning,
+ danger: $euiColorDanger,
+);
+
+// Create level modifiers based upon the map.
+@each $name, $color in $euiRange__levelColors {
+ .euiRange__level--#{$name} {
+ background-color: transparentize($color, .7);
+ }
+}
+
+.euiRange__range__progress {
+ height: 4px;
+ border-radius: 4px;
+ background-color: $euiRangeTrackColor;
+}
+
+.euiRange__value {
+ @include euiFontSizeS;
+ border: 1px solid transparentize($euiColorDarkestShade, .8);
+ position: absolute;
+ border-radius: $euiBorderRadius;
+ padding: $euiSizeXS $euiSizeS + 2px;
+ background-color: tintOrShade($euiColorFullShade, 25%, 90%);
+ color: $euiColorGhost;
+ max-width: 256px;
+ z-index: $euiZLevel4;
+ top: $euiFormControlHeight/2 - 1px;
+ transition:
+ box-shadow $euiAnimSpeedNormal $euiAnimSlightResistance,
+ transform $euiAnimSpeedNormal $euiAnimSlightResistance;
+
+ // Custom sizing
+ $arrowSize: $euiSizeM;
+ $arrowMinusSize: (($arrowSize/2) - 1px) * -1;
+
+ &::after,
+ &::before {
+ content: "";
+ position: absolute;
+ bottom: -$arrowSize/2;
+ left: 50%;
+ transform-origin: center;
+ background-color: tintOrShade($euiColorFullShade, 25%, 90%);
+ width: $arrowSize;
+ height: $arrowSize;
+ border-radius: 2px;
+ }
+
+ &::before {
+ background-color: transparentize($euiColorDarkestShade, .8);
+ }
+
+ // Positions the arrow
+ &.euiRange__value--right {
+ transform: translateX(0) translateY(-50%);
+ margin-left: $euiSizeL;
+
+ &:before,
+ &:after {
+ bottom: 50%;
+ left: $arrowMinusSize;
+ transform: translateY(50%) rotateZ(45deg);
+ }
+
+ &::before {
+ margin-left: -1px;
+ }
+ }
+
+ &.euiRange__value--left {
+ transform: translateX(-100%) translateY(-50%);
+ margin-left: -$euiSizeL;
+
+ &:before,
+ &:after {
+ bottom: 50%;
+ left: auto;
+ right: $arrowMinusSize;
+ transform: translateY(50%) rotateZ(45deg);
+ }
+
+ &::before {
+ margin-right: -1px;
+ }
+ }
+}
+
+
+/*
+ * Positioning
+ */
+
+.euiRange__wrapper--hasLevels {
+ .euiRange__levels {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: ($euiFormControlHeight/2) + 2px;
+ }
+}
+
+.euiRange__wrapper--hasRange {
+ .euiRange__range {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ top: ($euiFormControlHeight/2) - 2px;
+ z-index: $euiZLevel0;
+ overflow: hidden;
+ }
+}
+
+.euiRange__wrapper--hasTicks {
+ .euiRange {
+ height: $euiFormControlHeight/2; /* 3 */
+ }
+
+ .euiRange__levels {
+ top: ($euiFormControlHeight/4) + 2px;
+ }
+
+ .euiRange__range {
+ top: ($euiFormControlHeight/4) - 2px;
+ left: 0;
+ }
+
+ .euiRange__value {
+ top: ($euiFormControlHeight/4) - 1px;
+ }
+
+ .euiRange__extraInput {
+ margin-top: 0;
+ }
+
+ .euiRange__ticks {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: $euiSizeS;
+ display: flex;
+ z-index: $euiZLevel1;
+ }
+}
+
+.euiRange__valueWrapper {
+ // Keeps tooltip (value) aligned to percentage of actual slider
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: calc(100% - #{$euiRangeThumbWidth});
+ margin-left: $euiRangeThumbWidth/2;
+}
+
+/*
+ * Input Range Customization by browser
+ */
+
// The following code is inspired by...
// Github: https://github.com/darlanrod/input-range-sass
@@ -10,99 +274,92 @@
.euiRange {
// Auto means the height isn't defined
- @include euiFormControlSize(auto);
-
+ height: $euiFormControlHeight;
appearance: none;
- margin: $euiRangeThumbHeight / 2 0;
-
- &.euiRange--fullWidth {
- max-width: 100%;
- }
+ background: transparent; // Otherwise white in Chrome
+ width: 100%; // ensures the slider expands to fill flex display
+ position: relative;
+ z-index: $euiZLevel2; // stay above tick marks
+ cursor: pointer; // Keep cursor to full range bounds
&:disabled {
cursor: not-allowed;
- &::-webkit-slider-thumb {
- @include euiCustomControl--disabled;
- }
-
- &::-moz-range-thumb {
- @include euiCustomControl--disabled;
- }
-
- &::-ms-thumb {
- @include euiCustomControl--disabled;
- }
- &::-webkit-slider-runnable-track {
- background-color: $euiColorLightShade;
+ @include euiRange__thumb__perBrowser{
+ cursor: not-allowed;
+ border-color: $euiRangeThumbBorderColor;
+ background-color: $euiRangeThumbBorderColor;
+ box-shadow: none;
}
}
&:focus {
-
- &::-webkit-slider-thumb {
+ @include euiRange__thumb__perBrowser{
@include euiCustomControl--focused;
}
- &::-moz-range-thumb {
- @include euiCustomControl--focused;
+ @include euiRange__track__perBrowser{
+ background-color: $euiColorPrimary;
+ border-color: $euiColorPrimary;
}
- &::-ms-thumb {
- @include euiCustomControl--focused;
- }
- &::-webkit-slider-runnable-track {
+ ~ .euiRange__range .euiRange__range__progress {
background-color: $euiColorPrimary;
}
+ ~ .euiRange__valueWrapper .euiRange__value {
+ @include euiBottomShadow;
+
+ &.euiRange__value--right {
+ transform: translateX(0) translateY(-50%) scale(1.1);
+ }
+
+ &.euiRange__value--left {
+ transform: translateX(-100%) translateY(-50%) scale(1.1);
+ }
+ }
+ }
+
+ @include euiRange__thumb__perBrowser {
+ cursor: pointer;
+ @include euiCustomControl($type: 'round');
+ border-color: $euiRangeThumbBorderColor;
+ padding: 0;
+ height: $euiRangeThumbHeight;
+ width: $euiRangeThumbWidth;
}
- &::-webkit-slider-runnable-track {
- @include track;
+ @include euiRange__track__perBrowser {
+ @include euiRange__trackSize;
background: $euiRangeTrackColor;
border: $euiRangeTrackBorderWidth solid $euiRangeTrackBorderColor;
border-radius: $euiRangeTrackRadius;
}
+ // Resets
+
&::-webkit-slider-thumb {
- @include thumb;
-webkit-appearance: none;
margin-top: ((-$euiRangeTrackBorderWidth * 2 + $euiRangeTrackHeight) / 2) - ($euiRangeThumbHeight / 2);
}
- &::-moz-range-track {
- @include track;
- background: $euiRangeTrackColor;
- border: $euiRangeTrackBorderWidth solid $euiRangeTrackBorderColor;
- border-radius: $euiRangeTrackRadius;
- }
-
- &::-moz-range-thumb {
- @include thumb;
+ &::-ms-thumb {
+ margin-top: 0;
}
&::-ms-track {
- @include track;
+ @include euiRange__trackSize;
background: transparent;
border-color: transparent;
border-width: ($euiRangeThumbHeight / 2) 0;
color: transparent;
}
+}
- &::-ms-fill-lower {
- background: $euiRangeTrackColor;
- border: $euiRangeTrackBorderWidth solid $euiRangeTrackBorderColor;
- border-radius: $euiRangeTrackRadius * 2;
- }
-
- &::-ms-fill-upper {
- background: $euiRangeTrackColor;
- border: $euiRangeTrackBorderWidth solid $euiRangeTrackBorderColor;
- border-radius: $euiRangeTrackRadius * 2;
- }
-
- &::-ms-thumb {
- @include thumb;
- margin-top: 0;
+.euiRange__wrapper--hasRange .euiRange,
+.euiRange__wrapper--hasTicks .euiRange {
+ @include euiRange__track__perBrowser {
+ background-color: transparentize($euiRangeTrackColor, .6);
+ border-color: transparentize($euiRangeTrackBorderColor, .6);
}
}
diff --git a/src/components/form/range/_variables.scss b/src/components/form/range/_variables.scss
new file mode 100644
index 00000000000..8f66e5d2b27
--- /dev/null
+++ b/src/components/form/range/_variables.scss
@@ -0,0 +1,12 @@
+$euiRangeTrackColor: $euiColorDarkShade !default;
+
+$euiRangeThumbRadius: 50% !default;
+$euiRangeThumbHeight: $euiSize !default;
+$euiRangeThumbWidth: $euiSize !default;
+$euiRangeThumbBorderColor: $euiRangeTrackColor !default;
+
+$euiRangeTrackWidth: 100% !default;
+$euiRangeTrackHeight: 2px !default;
+$euiRangeTrackBorderWidth: 0 !default;
+$euiRangeTrackBorderColor: $euiRangeTrackColor !default;
+$euiRangeTrackRadius: $euiBorderRadius !default;
diff --git a/src/components/form/range/range.js b/src/components/form/range/range.js
index 394bdda9218..df4181013f6 100644
--- a/src/components/form/range/range.js
+++ b/src/components/form/range/range.js
@@ -1,39 +1,358 @@
-import React from 'react';
+import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-export const EuiRange = ({ className, compressed, id, name, min, max, fullWidth, value, ...rest }) => {
- const classes = classNames(
- 'euiRange',
- {
- 'euiRange--fullWidth': fullWidth,
- 'euiRange--compressed': compressed,
- },
- className
- );
+import { range } from 'lodash';
+
+import { EuiFieldNumber } from '../field_number';
+
+export const LEVEL_COLORS = ['primary', 'success', 'warning', 'danger'];
+
+export class EuiRange extends Component {
+ constructor(props) {
+ super(props);
+ }
+
+ render() {
+ const {
+ className,
+ compressed,
+ disabled,
+ fullWidth,
+ id,
+ max,
+ min,
+ name,
+ step,
+ showLabels,
+ showInput,
+ showTicks,
+ tickInterval,
+ levels,
+ showRange,
+ showValue,
+ onChange,
+ value,
+ style,
+ ...rest
+ } = this.props;
+
+ const classes = classNames(
+ 'euiRange',
+ {
+ 'euiRange--fullWidth': fullWidth,
+ 'euiRange--compressed': compressed,
+ },
+ className
+ );
+
+ const wrapperClasses = classNames(
+ 'euiRange__wrapper',
+ {
+ 'euiRange__wrapper--fullWidth': fullWidth,
+ 'euiRange__wrapper--compressed': compressed,
+ 'euiRange__wrapper--disabled': disabled,
+ 'euiRange__wrapper--hasLabels': showLabels,
+ 'euiRange__wrapper--hasLevels': levels.length,
+ 'euiRange__wrapper--hasRange': showRange,
+ 'euiRange__wrapper--hasTicks': showTicks,
+ 'euiRange__wrapper--hasValue': showValue,
+ },
+ );
+
+ let sliderTabIndex;
+ let extraInputNode;
+ if (showInput) {
+ // Chrome will properly size the input based on the max value, but FF & IE does not.
+ // Calculate the max-width of the input based on number of characters in max unit
+ // Add 2 to accomodate for input stepper
+ const maxWidthStyle = { maxWidth: `${String(max).length + 2}em` };
+
+ // Make this input the main control by disabling screen reader access to slider control
+ sliderTabIndex = '-1';
+
+ extraInputNode = (
+
+ );
+ }
+
+ let tickObject;
+ const inputWrapperStyle = {};
+ if (showTicks) {
+ tickObject = calculateTicksObject(min, max, tickInterval || step || 1);
+
+ // Calculate if any extra margin should be added to the inputWrapper
+ // because of longer tick labels on the ends
+ const lengthOfMinLabel = String(tickObject.sequence[0]).length;
+ const lenghtOfMaxLabel = String(tickObject.sequence[tickObject.sequence.length - 1]).length;
+ const isLastTickTheMax = tickObject.sequence[tickObject.sequence.length - 1] === max;
+ if (lengthOfMinLabel > 2) {
+ inputWrapperStyle.marginLeft = `${(lengthOfMinLabel / 5)}em`;
+ }
+ if (isLastTickTheMax && lenghtOfMaxLabel > 2) {
+ inputWrapperStyle.marginRight = `${(lenghtOfMaxLabel / 5)}em`;
+ }
+ }
+
+ return (
+
+ {this.renderLabel('min')}
+
+
+
+
+ {this.renderValue()}
+ {this.renderRange()}
+ {this.renderLevels()}
+ {this.renderTicks(tickObject)}
+
+
+ {this.renderLabel('max')}
+ {extraInputNode}
+
+ );
+ }
+
+ renderLabel = (side) => {
+ const {
+ showLabels,
+ } = this.props;
+
+ if (!showLabels) { return; }
+
+ return (
+
+ {this.props[side]}
+
+ );
+
+ }
+
+ renderTicks = (tickObject) => {
+ const {
+ disabled,
+ onChange,
+ showTicks,
+ value
+ } = this.props;
+
+ if (!showTicks) {
+ return;
+ }
+
+ // Align with item labels across the range by adding
+ // left and right negative margins that is half of the tick marks
+ const ticksStyle = { margin: `0 ${tickObject.percentageWidth / -2}%` };
+
+ return (
+
+ {tickObject.sequence.map((tickValue, index) => {
+ const tickClasses = classNames(
+ 'euiRange__tick',
+ { 'euiRange__tick--selected': value === tickValue, }
+ );
+
+ return (
+
+ {tickValue}
+
+ );
+ })}
+
+ );
+ }
+
+ renderRange = () => {
+ const {
+ showRange,
+ value,
+ max,
+ min,
+ } = this.props;
+
+ if (!showRange) {
+ return;
+ }
+
+ // Calculate the width the range based on value
+ const rangeWidth = (value - min) / (max - min);
+ const rangeWidthStyle = { width: `${rangeWidth * 100}%` };
+
+ return (
+
+ );
+ }
+
+ renderValue = () => {
+ const {
+ showValue,
+ value,
+ max,
+ min,
+ name,
+ } = this.props;
+
+ if (!showValue) {
+ return;
+ }
+
+ // Calculate the left position based on value
+ const decimal = (value - min) / (max - min);
+ // Must be between 0-100%
+ let valuePosition = decimal <= 1 ? decimal : 1;
+ valuePosition = valuePosition >= 0 ? valuePosition : 0;
+
+ let valuePositionSide;
+ if (valuePosition > .5) {
+ valuePositionSide = 'left';
+ } else {
+ valuePositionSide = 'right';
+ }
+
+ const valuePositionStyle = { left: `${valuePosition * 100}%` };
+
+ // Change left/right position based on value (half way point)
+ const valueClasses = classNames(
+ 'euiRange__value',
+ `euiRange__value--${valuePositionSide}`,
+ );
+
+ return (
+
+
+ {value}
+
+
+ );
+ }
+
+ renderLevels = () => {
+ const {
+ levels,
+ max,
+ min,
+ } = this.props;
+
+ if (levels.length < 1) {
+ return;
+ }
+
+ return (
+
+ {levels.map((level, index) => {
+ const range = level.max - level.min;
+ const width = (range / (max - min)) * 100;
+
+ return (
+
+ );
+ })}
+
+ );
+ }
+}
+
+function calculateTicksObject(min, max, interval) {
+ // Calculate the width of each tick mark
+ const tickWidthDecimal = (interval / ((max - min) + interval));
+ const tickWidthPercentage = tickWidthDecimal * 100;
+
+ // Loop from min to max, creating ticks at each interval
+ // (adds a very small number to the max since `range` is not inclusive of the max value)
+ const toBeInclusive = .000000001;
+ const sequence = range(min, max + toBeInclusive, interval);
return (
-
+ {
+ decimalWidth: tickWidthDecimal,
+ percentageWidth: tickWidthPercentage,
+ sequence: sequence,
+ }
);
-};
+}
EuiRange.propTypes = {
name: PropTypes.string,
id: PropTypes.string,
min: PropTypes.number.isRequired,
max: PropTypes.number.isRequired,
+ step: PropTypes.number,
value: PropTypes.string,
fullWidth: PropTypes.bool,
compressed: PropTypes.bool,
+ /**
+ * Shows static min/max labels on the sides of the range slider
+ */
+ showLabels: PropTypes.bool,
+ /**
+ * Displays an extra input control for direct manipulation
+ */
+ showInput: PropTypes.bool,
+ /**
+ * Shows clickable tick marks and labels at the given interval (`step`/`tickInterval`)
+ */
+ showTicks: PropTypes.bool,
+ /**
+ * Modifies the number of tick marks and at what interval
+ */
+ tickInterval: PropTypes.number,
+ onChange: PropTypes.func,
+ /**
+ * Create colored indicators for certain intervals
+ */
+ levels: PropTypes.arrayOf(
+ PropTypes.shape({
+ min: PropTypes.number,
+ max: PropTypes.number,
+ color: PropTypes.oneOf(LEVEL_COLORS),
+ }),
+ ),
+ /**
+ * Shows a thick line from min to value
+ */
+ showRange: PropTypes.bool,
+ /**
+ * Shows a tooltip styled value
+ */
+ showValue: PropTypes.bool,
};
EuiRange.defaultProps = {
@@ -41,4 +360,9 @@ EuiRange.defaultProps = {
max: 100,
fullWidth: false,
compressed: false,
+ showLabels: false,
+ showInput: false,
+ showTicks: false,
+ showValue: false,
+ levels: [],
};
diff --git a/src/components/form/range/range.test.js b/src/components/form/range/range.test.js
index 5b78e36497f..172835f791b 100644
--- a/src/components/form/range/range.test.js
+++ b/src/components/form/range/range.test.js
@@ -12,7 +12,7 @@ describe('EuiRange', () => {
id="id"
min={1}
max={10}
- value="value"
+ value="8"
onChange={() => {}}
{...requiredProps}
/>
@@ -31,5 +31,90 @@ describe('EuiRange', () => {
expect(component)
.toMatchSnapshot();
});
+
+ test('compressed should render', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('labels should render', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('ticks should render', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('range should render', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('value should render', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('extra input should render', () => {
+ const component = render(
+ {}}
+ showInput
+ {...requiredProps}
+ />
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
+
+ test('levels should render', () => {
+ const component = render(
+
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+ });
});
});
diff --git a/src/global_styling/mixins/_shadow.scss b/src/global_styling/mixins/_shadow.scss
index 3470e4816ee..59bb18f9ba8 100644
--- a/src/global_styling/mixins/_shadow.scss
+++ b/src/global_styling/mixins/_shadow.scss
@@ -1,7 +1,6 @@
$euiShadowColor: $euiColorMediumShade !default;
$euiShadowColorLarge: $euiColorSlightHue !default;
-
@mixin euiSlightShadow($color: $euiShadowColor, $opacity: .3) {
box-shadow: 0 2px 2px -1px rgba($color, $opacity);
}