feat: improved range slider
This commit is contained in:
parent
4c666bb438
commit
621f4c72f4
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`renders <Filters /> without throwing 1`] = `
|
exports[`renders <Filters /> without throwing 1`] = `
|
||||||
.c6 {
|
.c12 {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
@ -49,47 +49,47 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c6::-moz-focus-inner,
|
.c12::-moz-focus-inner,
|
||||||
.c6[type='button']::-moz-focus-inner,
|
.c12[type='button']::-moz-focus-inner,
|
||||||
.c6[type='reset']::-moz-focus-inner,
|
.c12[type='reset']::-moz-focus-inner,
|
||||||
.c6[type='submit']::-moz-focus-inner {
|
.c12[type='submit']::-moz-focus-inner {
|
||||||
border-style: none;
|
border-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c6:-moz-focusring,
|
.c12:-moz-focusring,
|
||||||
.c6[type='button']:-moz-focusring,
|
.c12[type='button']:-moz-focusring,
|
||||||
.c6[type='reset']:-moz-focusring,
|
.c12[type='reset']:-moz-focusring,
|
||||||
.c6[type='submit']:-moz-focusring {
|
.c12[type='submit']:-moz-focusring {
|
||||||
outline: 0.0625rem dotted ButtonText;
|
outline: 0.0625rem dotted ButtonText;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c6:focus {
|
.c12:focus {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c6:hover {
|
.c12:hover {
|
||||||
border: solid 0.0625rem;
|
border: solid 0.0625rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c6:active,
|
.c12:active,
|
||||||
.c6:active:hover,
|
.c12:active:hover,
|
||||||
.c6:active:focus {
|
.c12:active:focus {
|
||||||
background-image: none;
|
background-image: none;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c6[disabled] {
|
.c12[disabled] {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c6 + button {
|
.c12 + button {
|
||||||
margin-left: 1.25rem;
|
margin-left: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7 {
|
.c13 {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
line-height: 1.15;
|
line-height: 1.15;
|
||||||
@ -136,43 +136,43 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7::-moz-focus-inner,
|
.c13::-moz-focus-inner,
|
||||||
.c7[type='button']::-moz-focus-inner,
|
.c13[type='button']::-moz-focus-inner,
|
||||||
.c7[type='reset']::-moz-focus-inner,
|
.c13[type='reset']::-moz-focus-inner,
|
||||||
.c7[type='submit']::-moz-focus-inner {
|
.c13[type='submit']::-moz-focus-inner {
|
||||||
border-style: none;
|
border-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7:-moz-focusring,
|
.c13:-moz-focusring,
|
||||||
.c7[type='button']:-moz-focusring,
|
.c13[type='button']:-moz-focusring,
|
||||||
.c7[type='reset']:-moz-focusring,
|
.c13[type='reset']:-moz-focusring,
|
||||||
.c7[type='submit']:-moz-focusring {
|
.c13[type='submit']:-moz-focusring {
|
||||||
outline: 0.0625rem dotted ButtonText;
|
outline: 0.0625rem dotted ButtonText;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7:focus {
|
.c13:focus {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7:hover {
|
.c13:hover {
|
||||||
border: solid 0.0625rem;
|
border: solid 0.0625rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7:active,
|
.c13:active,
|
||||||
.c7:active:hover,
|
.c13:active:hover,
|
||||||
.c7:active:focus {
|
.c13:active:focus {
|
||||||
background-image: none;
|
background-image: none;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7[disabled] {
|
.c13[disabled] {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7 + button {
|
.c13 + button {
|
||||||
margin-left: 1.25rem;
|
margin-left: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,14 +187,25 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .input-range {
|
.c7 {
|
||||||
position: relative;
|
font-weight: 600;
|
||||||
width: calc(100% - 18px);
|
font-size: 0.625rem;
|
||||||
margin: auto;
|
color: #464646;
|
||||||
min-height: 0.625rem;
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .slider {
|
.c9 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.625rem;
|
||||||
|
color: #464646;
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c8 {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
@ -205,57 +216,56 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
display: block;
|
display: block;
|
||||||
height: 0.875rem;
|
height: 0.875rem;
|
||||||
width: 0.875rem;
|
width: 0.875rem;
|
||||||
-webkit-transform: translateY(-50%) translateX(-50%);
|
-webkit-transform: translateY(-50%) translateX(-1%);
|
||||||
-ms-transform: translateY(-50%) translateX(-50%);
|
-ms-transform: translateY(-50%) translateX(-1%);
|
||||||
transform: translateY(-50%) translateX(-50%);
|
transform: translateY(-50%) translateX(-1%);
|
||||||
outline: none;
|
outline: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 0;
|
||||||
margin-top: 0.125rem;
|
margin-top: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .slider::active {
|
.c8::active {
|
||||||
-webkit-transform: scale(1.3);
|
-webkit-transform: scale(1.3);
|
||||||
-ms-transform: scale(1.3);
|
-ms-transform: scale(1.3);
|
||||||
transform: scale(1.3);
|
transform: scale(1.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .slider::focus {
|
.c8::focus {
|
||||||
box-shadow: 0 0 0 5px rgba(63,81,181,0.2);
|
box-shadow: 0 0 0 5px rgba(63,81,181,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .disabled .track {
|
.c10 {
|
||||||
background: #D8D8D8;
|
-webkit-appearance: none;
|
||||||
}
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
.c3 .disabled .slider {
|
background: #FFFFFF;
|
||||||
background: #CCC;
|
border: 2px solid #bdbdbd;
|
||||||
border: 1px solid #CCC;
|
border-radius: 50%;
|
||||||
box-shadow: none;
|
cursor: pointer;
|
||||||
-webkit-transform: none;
|
display: block;
|
||||||
-ms-transform: none;
|
height: 0.875rem;
|
||||||
transform: none;
|
width: 0.875rem;
|
||||||
}
|
-webkit-transform: translateY(-50%) translateX(-99%);
|
||||||
|
-ms-transform: translateY(-50%) translateX(-99%);
|
||||||
.c3 .min,
|
transform: translateY(-50%) translateX(-99%);
|
||||||
.c3 .max {
|
outline: none;
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c3 .value {
|
|
||||||
top: 0.5rem;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
margin-top: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .value .label-container {
|
.c10::active {
|
||||||
font-weight: 600;
|
-webkit-transform: scale(1.3);
|
||||||
font-size: 0.625rem;
|
-ms-transform: scale(1.3);
|
||||||
color: #464646;
|
transform: scale(1.3);
|
||||||
left: -50%;
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .track {
|
.c10::focus {
|
||||||
|
box-shadow: 0 0 0 5px rgba(63,81,181,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.c5 {
|
||||||
background: #D8D8D8;
|
background: #D8D8D8;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block;
|
display: block;
|
||||||
@ -263,13 +273,18 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3 .active-track {
|
.c6 {
|
||||||
background: #364ACD;
|
background: #364ACD;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c4 {
|
.c4 {
|
||||||
|
position: relative;
|
||||||
|
min-height: 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c3 {
|
||||||
margin-bottom: 0.625rem;
|
margin-bottom: 0.625rem;
|
||||||
margin-top: 0.75rem;
|
margin-top: 0.75rem;
|
||||||
}
|
}
|
||||||
@ -291,7 +306,7 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
margin-right: 2.25rem;
|
margin-right: 2.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c5 {
|
.c11 {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
@ -320,39 +335,28 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
<section
|
<section
|
||||||
className="c2"
|
className="c2"
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
className="c3"
|
|
||||||
>
|
|
||||||
<label
|
<label
|
||||||
className="c4 c1"
|
className="c3 c1"
|
||||||
htmlFor=""
|
htmlFor=""
|
||||||
>
|
>
|
||||||
GB RAM
|
GB RAM
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
aria-disabled={false}
|
aria-disabled={false}
|
||||||
className="input-range"
|
className="c4"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
className="min"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
0.256
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
className="track"
|
className="c5"
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="active-track"
|
className="c6"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "0%",
|
"left": "0%",
|
||||||
@ -360,117 +364,89 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="slider-container"
|
className="c7"
|
||||||
style={
|
type="min"
|
||||||
Object {
|
|
||||||
"left": "0%",
|
|
||||||
"position": "absolute",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="value"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
0.256
|
0.256
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={50.688}
|
aria-valuemax={50.688}
|
||||||
aria-valuemin={0.256}
|
aria-valuemin={0.256}
|
||||||
aria-valuenow={0.256}
|
aria-valuenow={0.256}
|
||||||
className="slider"
|
className="c8"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
tabIndex="0"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
className="slider-container"
|
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "100%",
|
"left": "0%",
|
||||||
"position": "absolute",
|
"position": "absolute",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
tabIndex="0"
|
||||||
|
type="min"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="value"
|
className="c9"
|
||||||
>
|
type="max"
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
50.688
|
50.688
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={50.688}
|
aria-valuemax={50.688}
|
||||||
aria-valuemin={0.256}
|
aria-valuemin={0.256}
|
||||||
aria-valuenow={50.688}
|
aria-valuenow={50.688}
|
||||||
className="slider"
|
className="c10"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"left": "100%",
|
||||||
|
"position": "absolute",
|
||||||
|
}
|
||||||
|
}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
|
type="max"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
|
||||||
className="max"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
50.688
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div>
|
||||||
className="c3"
|
|
||||||
>
|
|
||||||
<label
|
<label
|
||||||
className="c4 c1"
|
className="c3 c1"
|
||||||
htmlFor=""
|
htmlFor=""
|
||||||
>
|
>
|
||||||
vCPUs
|
vCPUs
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
aria-disabled={false}
|
aria-disabled={false}
|
||||||
className="input-range"
|
className="c4"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
className="min"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
0.25
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
className="track"
|
className="c5"
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="active-track"
|
className="c6"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "0%",
|
"left": "0%",
|
||||||
@ -478,117 +454,89 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="slider-container"
|
className="c7"
|
||||||
style={
|
type="min"
|
||||||
Object {
|
|
||||||
"left": "0%",
|
|
||||||
"position": "absolute",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="value"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
0.25
|
0.25
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={3.25}
|
aria-valuemax={3.25}
|
||||||
aria-valuemin={0.25}
|
aria-valuemin={0.25}
|
||||||
aria-valuenow={0.25}
|
aria-valuenow={0.25}
|
||||||
className="slider"
|
className="c8"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
tabIndex="0"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
className="slider-container"
|
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "100%",
|
"left": "0%",
|
||||||
"position": "absolute",
|
"position": "absolute",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
tabIndex="0"
|
||||||
|
type="min"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="value"
|
className="c9"
|
||||||
>
|
type="max"
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
3.25
|
3.25
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={3.25}
|
aria-valuemax={3.25}
|
||||||
aria-valuemin={0.25}
|
aria-valuemin={0.25}
|
||||||
aria-valuenow={3.25}
|
aria-valuenow={3.25}
|
||||||
className="slider"
|
className="c10"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"left": "100%",
|
||||||
|
"position": "absolute",
|
||||||
|
}
|
||||||
|
}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
|
type="max"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
|
||||||
className="max"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
3.25
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div>
|
||||||
className="c3"
|
|
||||||
>
|
|
||||||
<label
|
<label
|
||||||
className="c4 c1"
|
className="c3 c1"
|
||||||
htmlFor=""
|
htmlFor=""
|
||||||
>
|
>
|
||||||
TB Disk
|
TB Disk
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
aria-disabled={false}
|
aria-disabled={false}
|
||||||
className="input-range"
|
className="c4"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
className="min"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
0.01
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
className="track"
|
className="c5"
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="active-track"
|
className="c6"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "0%",
|
"left": "0%",
|
||||||
@ -596,117 +544,89 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="slider-container"
|
className="c7"
|
||||||
style={
|
type="min"
|
||||||
Object {
|
|
||||||
"left": "0%",
|
|
||||||
"position": "absolute",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="value"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
0.01
|
0.01
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={107.26}
|
aria-valuemax={107.26}
|
||||||
aria-valuemin={0.01}
|
aria-valuemin={0.01}
|
||||||
aria-valuenow={0.01}
|
aria-valuenow={0.01}
|
||||||
className="slider"
|
className="c8"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
tabIndex="0"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
className="slider-container"
|
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "100%",
|
"left": "0%",
|
||||||
"position": "absolute",
|
"position": "absolute",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
tabIndex="0"
|
||||||
|
type="min"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="value"
|
className="c9"
|
||||||
>
|
type="max"
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
107.26
|
107.26
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={107.26}
|
aria-valuemax={107.26}
|
||||||
aria-valuemin={0.01}
|
aria-valuemin={0.01}
|
||||||
aria-valuenow={107.26}
|
aria-valuenow={107.26}
|
||||||
className="slider"
|
className="c10"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"left": "100%",
|
||||||
|
"position": "absolute",
|
||||||
|
}
|
||||||
|
}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
|
type="max"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
|
||||||
className="max"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
107.26
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div>
|
||||||
className="c3"
|
|
||||||
>
|
|
||||||
<label
|
<label
|
||||||
className="c4 c1"
|
className="c3 c1"
|
||||||
htmlFor=""
|
htmlFor=""
|
||||||
>
|
>
|
||||||
$/hr
|
$/hr
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div
|
||||||
aria-disabled={false}
|
aria-disabled={false}
|
||||||
className="input-range"
|
className="c4"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onKeyUp={[Function]}
|
onKeyUp={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
className="min"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
0.016
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
className="track"
|
className="c5"
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="active-track"
|
className="c6"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "0%",
|
"left": "0%",
|
||||||
@ -714,112 +634,95 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="slider-container"
|
className="c7"
|
||||||
style={
|
type="min"
|
||||||
Object {
|
|
||||||
"left": "0%",
|
|
||||||
"position": "absolute",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="value"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
0.016
|
0.016
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={0.525}
|
aria-valuemax={0.525}
|
||||||
aria-valuemin={0.016}
|
aria-valuemin={0.016}
|
||||||
aria-valuenow={0.016}
|
aria-valuenow={0.016}
|
||||||
className="slider"
|
className="c8"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
tabIndex="0"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
className="slider-container"
|
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"left": "100%",
|
"left": "0%",
|
||||||
"position": "absolute",
|
"position": "absolute",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
tabIndex="0"
|
||||||
|
type="min"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
<span
|
<span
|
||||||
className="value"
|
className="c9"
|
||||||
>
|
type="max"
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
>
|
||||||
0.525
|
0.525
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
<div
|
<div
|
||||||
aria-controls={undefined}
|
aria-controls={undefined}
|
||||||
aria-labelledby={undefined}
|
aria-labelledby={undefined}
|
||||||
aria-valuemax={0.525}
|
aria-valuemax={0.525}
|
||||||
aria-valuemin={0.016}
|
aria-valuemin={0.016}
|
||||||
aria-valuenow={0.525}
|
aria-valuenow={0.525}
|
||||||
className="slider"
|
className="c10"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onMouseDown={[Function]}
|
onMouseDown={[Function]}
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
role="slider"
|
role="slider"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"left": "100%",
|
||||||
|
"position": "absolute",
|
||||||
|
}
|
||||||
|
}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
|
type="max"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
|
||||||
className="max"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="label-container"
|
|
||||||
>
|
|
||||||
0.525
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
className="c5"
|
className="c11"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
className="c6"
|
className="c12"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
selected={false}
|
selected={false}
|
||||||
>
|
>
|
||||||
Compute Optimized
|
Compute Optimized
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="c6"
|
className="c12"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
selected={false}
|
selected={false}
|
||||||
>
|
>
|
||||||
General Purpose
|
General Purpose
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="c6"
|
className="c12"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
selected={false}
|
selected={false}
|
||||||
>
|
>
|
||||||
Memory Optimized
|
Memory Optimized
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="c6"
|
className="c12"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
selected={false}
|
selected={false}
|
||||||
>
|
>
|
||||||
@ -827,7 +730,7 @@ exports[`renders <Filters /> without throwing 1`] = `
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="c7"
|
className="c13"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
onClick={undefined}
|
onClick={undefined}
|
||||||
>
|
>
|
||||||
|
@ -1,9 +1,21 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Row } from 'react-styled-flexboxgrid';
|
import { Row } from 'react-styled-flexboxgrid';
|
||||||
|
import styled from 'styled-components';
|
||||||
import { SectionNav } from '@components/navigation';
|
import { SectionNav } from '@components/navigation';
|
||||||
import { Filters } from '@components/filters';
|
import { Filters } from '@components/filters';
|
||||||
import PackagesHOC from '@containers/packages';
|
import PackagesHOC from '@containers/packages';
|
||||||
import { Message, Breadcrumb, BreadcrumbItem, Anchor } from 'joyent-ui-toolkit';
|
import {
|
||||||
|
Message,
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbItem,
|
||||||
|
Anchor,
|
||||||
|
Button
|
||||||
|
} from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
|
const Main = styled.main`
|
||||||
|
/* Prettier stahp */
|
||||||
|
margin-bottom: 40px;
|
||||||
|
`
|
||||||
|
|
||||||
class Home extends Component {
|
class Home extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -38,10 +50,7 @@ class Home extends Component {
|
|||||||
|
|
||||||
onFilterChange({
|
onFilterChange({
|
||||||
...filters,
|
...filters,
|
||||||
groups: [
|
groups: [...otherGroups, { name: group.name, selected: !group.selected }]
|
||||||
...otherGroups,
|
|
||||||
{ name: group.name, selected: !group.selected }
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +69,7 @@ class Home extends Component {
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<Main>
|
||||||
<SectionNav />
|
<SectionNav />
|
||||||
<Breadcrumb>
|
<Breadcrumb>
|
||||||
<BreadcrumbItem>Instances</BreadcrumbItem>
|
<BreadcrumbItem>Instances</BreadcrumbItem>
|
||||||
@ -81,7 +90,11 @@ class Home extends Component {
|
|||||||
<Row>
|
<Row>
|
||||||
<PackagesHOC />
|
<PackagesHOC />
|
||||||
</Row>
|
</Row>
|
||||||
</main>
|
<Row>
|
||||||
|
<Button secondary>Cancel</Button>
|
||||||
|
<Button>Save and Continue</Button>
|
||||||
|
</Row>
|
||||||
|
</Main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,11 @@ exports[`renders <Header /> without throwing 1`] = `
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="/"
|
||||||
|
name="Go to home"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
|
alt="Triton Logo"
|
||||||
className="c3"
|
className="c3"
|
||||||
src="test-file-mock"
|
src="test-file-mock"
|
||||||
/>
|
/>
|
||||||
|
@ -14,8 +14,8 @@ const StyledLogo = Img.extend`
|
|||||||
const NavHeader = () => (
|
const NavHeader = () => (
|
||||||
<Header>
|
<Header>
|
||||||
<HeaderBrand>
|
<HeaderBrand>
|
||||||
<Link to="/">
|
<Link to="/" name="Go to home">
|
||||||
<StyledLogo src={Logo} />
|
<StyledLogo src={Logo} alt="Triton Logo"/>
|
||||||
</Link>
|
</Link>
|
||||||
</HeaderBrand>
|
</HeaderBrand>
|
||||||
</Header>
|
</Header>
|
||||||
|
@ -253,7 +253,7 @@ exports[`renders <Packages /> without throwing 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<ul
|
<section
|
||||||
className="c0"
|
className="c0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -760,5 +760,5 @@ exports[`renders <Packages /> without throwing 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</section>
|
||||||
`;
|
`;
|
||||||
|
@ -5,7 +5,7 @@ import { Col } from 'react-styled-flexboxgrid';
|
|||||||
|
|
||||||
import Package from '@components/package';
|
import Package from '@components/package';
|
||||||
|
|
||||||
const ListStyled = styled.ul`
|
const ListStyled = styled.section`
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -68,9 +68,11 @@ exports[`renders <Header /> without throwing 1`] = `
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="/"
|
||||||
|
name="Go to home"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
|
alt="Triton Logo"
|
||||||
className="c3"
|
className="c3"
|
||||||
src="test-file-mock"
|
src="test-file-mock"
|
||||||
/>
|
/>
|
||||||
|
@ -253,7 +253,7 @@ exports[`renders <PackagesHOC /> without throwing 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<ul
|
<section
|
||||||
className="c0"
|
className="c0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -1768,5 +1768,5 @@ exports[`renders <PackagesHOC /> without throwing 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</section>
|
||||||
`;
|
`;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"presets": "joyent-portal",
|
"presets": ["joyent-portal"],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"styled-components",
|
"styled-components",
|
||||||
["inline-react-svg", {
|
["inline-react-svg", {
|
||||||
|
@ -10,22 +10,16 @@
|
|||||||
"lint:css": "echo 0",
|
"lint:css": "echo 0",
|
||||||
"lint-ci:css": "echo 0",
|
"lint-ci:css": "echo 0",
|
||||||
"lint:js": "eslint . --fix",
|
"lint:js": "eslint . --fix",
|
||||||
"lint-ci:js":
|
"lint-ci:js": "eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/ui-toolkit.xml",
|
||||||
"eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/ui-toolkit.xml",
|
|
||||||
"lint": "redrun -s lint:*",
|
"lint": "redrun -s lint:*",
|
||||||
"lint-ci": "redrun -s lint-ci:*",
|
"lint-ci": "redrun -s lint-ci:*",
|
||||||
"test": "echo 0",
|
"test": "echo 0",
|
||||||
"test-ci": "echo 0",
|
"test-ci": "echo 0",
|
||||||
"copy-fonts":
|
"copy-fonts": "rm -rf dist; mkdir -p dist/es/typography; mkdir -p dist/umd/typography; cp -r src/typography/libre-franklin dist/es/typography; cp -r src/typography/libre-franklin dist/umd/typography",
|
||||||
"rm -rf dist; mkdir -p dist/es/typography; mkdir -p dist/umd/typography; cp -r src/typography/libre-franklin dist/es/typography; cp -r src/typography/libre-franklin dist/umd/typography",
|
"compile-watch:es": "NODE_ENV=development babel src --out-dir dist/es --source-maps inline --watch",
|
||||||
"compile-watch:es":
|
"compile:es": "NODE_ENV=development babel src --out-dir dist/es --source-maps inline",
|
||||||
"NODE_ENV=development babel src --out-dir dist/es --source-maps inline --watch",
|
"compile:umd": "cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline",
|
||||||
"compile:es":
|
"compile-watch:umd": "cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline --watch",
|
||||||
"NODE_ENV=development babel src --out-dir dist/es --source-maps inline",
|
|
||||||
"compile:umd":
|
|
||||||
"cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline",
|
|
||||||
"compile-watch:umd":
|
|
||||||
"cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline --watch",
|
|
||||||
"compile": "redrun -p compile:*",
|
"compile": "redrun -p compile:*",
|
||||||
"watch": "redrun copy-fonts && redrun -p compile-watch:*",
|
"watch": "redrun copy-fonts && redrun -p compile-watch:*",
|
||||||
"styleguide:build": "cross-env NODE_ENV=production styleguidist build",
|
"styleguide:build": "cross-env NODE_ENV=production styleguidist build",
|
||||||
@ -64,6 +58,7 @@
|
|||||||
"unitcalc": "^1.0.8"
|
"unitcalc": "^1.0.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||||
"csso": "^3.1.1",
|
"csso": "^3.1.1",
|
||||||
"eslint": "^4.5.0",
|
"eslint": "^4.5.0",
|
||||||
"eslint-config-joyent-portal": "2.0.0",
|
"eslint-config-joyent-portal": "2.0.0",
|
||||||
@ -88,8 +83,7 @@
|
|||||||
"stylelint": "^8.0.0",
|
"stylelint": "^8.0.0",
|
||||||
"stylelint-config-primer": "^2.0.1",
|
"stylelint-config-primer": "^2.0.1",
|
||||||
"stylelint-config-standard": "^17.0.0",
|
"stylelint-config-standard": "^17.0.0",
|
||||||
"stylelint-processor-styled-components":
|
"stylelint-processor-styled-components": "styled-components/stylelint-processor-styled-components#2a33b5f",
|
||||||
"styled-components/stylelint-processor-styled-components#2a33b5f",
|
|
||||||
"svgo": "^0.7.2",
|
"svgo": "^0.7.2",
|
||||||
"tinycolor2": "^1.4.1",
|
"tinycolor2": "^1.4.1",
|
||||||
"title-case": "^2.1.1",
|
"title-case": "^2.1.1",
|
||||||
|
@ -10,16 +10,3 @@
|
|||||||
onChange={value => console.log(value)}
|
onChange={value => console.log(value)}
|
||||||
>vCPUs</Slider>
|
>vCPUs</Slider>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Normal Slider
|
|
||||||
|
|
||||||
```
|
|
||||||
<Slider
|
|
||||||
minValue={10}
|
|
||||||
maxValue={100}
|
|
||||||
step={5}
|
|
||||||
value={0}
|
|
||||||
onChangeComplete={value => console.log(value)}
|
|
||||||
onChange={value => console.log(value)}
|
|
||||||
>Price</Slider>
|
|
||||||
```
|
|
||||||
|
@ -1,57 +1,10 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import InputRange from 'react-input-range';
|
import InputRange from './react-input-range';
|
||||||
import remcalc from 'remcalc';
|
import remcalc from 'remcalc';
|
||||||
|
|
||||||
import theme from '../theme';
|
|
||||||
import FormLabel from '../form/label';
|
import FormLabel from '../form/label';
|
||||||
import {
|
|
||||||
sliderStyles,
|
|
||||||
disabledStyles,
|
|
||||||
trackStyles,
|
|
||||||
activeStyles,
|
|
||||||
rangeStyles
|
|
||||||
} from './inputStyles';
|
|
||||||
|
|
||||||
const SliderStyled = styled.div`
|
|
||||||
.input-range {
|
|
||||||
${rangeStyles};
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider {
|
|
||||||
${sliderStyles};
|
|
||||||
}
|
|
||||||
.disabled {
|
|
||||||
${disabledStyles};
|
|
||||||
}
|
|
||||||
|
|
||||||
.min,
|
|
||||||
.max {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
|
||||||
top: ${remcalc(8)};
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
.label-container {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: ${remcalc(10)};
|
|
||||||
color: ${theme.secondary};
|
|
||||||
left: -50%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.track {
|
|
||||||
${trackStyles};
|
|
||||||
}
|
|
||||||
|
|
||||||
.active-track {
|
|
||||||
${activeStyles};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Label = styled(FormLabel)`
|
const Label = styled(FormLabel)`
|
||||||
margin-bottom: ${remcalc(10)};
|
margin-bottom: ${remcalc(10)};
|
||||||
@ -79,7 +32,7 @@ class Slider extends Component {
|
|||||||
const { minValue, maxValue, value } = this.state;
|
const { minValue, maxValue, value } = this.state;
|
||||||
const { children, ...rest } = this.props;
|
const { children, ...rest } = this.props;
|
||||||
return (
|
return (
|
||||||
<SliderStyled>
|
<div>
|
||||||
<Label>{children}</Label>
|
<Label>{children}</Label>
|
||||||
<InputRange
|
<InputRange
|
||||||
{...rest}
|
{...rest}
|
||||||
@ -88,7 +41,7 @@ class Slider extends Component {
|
|||||||
value={value}
|
value={value}
|
||||||
onChange={value => this.changeValue(value)}
|
onChange={value => this.changeValue(value)}
|
||||||
/>
|
/>
|
||||||
</SliderStyled>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,18 +56,6 @@ Slider.propTypes = {
|
|||||||
formatLabel: PropTypes.func,
|
formatLabel: PropTypes.func,
|
||||||
ariaLabelledby: PropTypes.string,
|
ariaLabelledby: PropTypes.string,
|
||||||
ariaControls: PropTypes.string,
|
ariaControls: PropTypes.string,
|
||||||
classNames: PropTypes.shape({
|
|
||||||
activeTrack: PropTypes.string,
|
|
||||||
disabledInputRange: PropTypes.string,
|
|
||||||
inputRange: PropTypes.string,
|
|
||||||
labelContainer: PropTypes.string,
|
|
||||||
maxLabel: PropTypes.string,
|
|
||||||
minLabel: PropTypes.string,
|
|
||||||
slider: PropTypes.string,
|
|
||||||
sliderContainer: PropTypes.string,
|
|
||||||
track: PropTypes.string,
|
|
||||||
valueLabel: PropTypes.string
|
|
||||||
}),
|
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
draggableTrack: PropTypes.bool,
|
draggableTrack: PropTypes.bool,
|
||||||
onChangeStart: PropTypes.func,
|
onChangeStart: PropTypes.func,
|
||||||
@ -129,19 +70,7 @@ Slider.defaultProps = {
|
|||||||
? Math.round(value).toFixed(3)
|
? Math.round(value).toFixed(3)
|
||||||
: value,
|
: value,
|
||||||
onChangeStart: () => {},
|
onChangeStart: () => {},
|
||||||
step: 1,
|
step: 1
|
||||||
classNames: {
|
|
||||||
activeTrack: 'active-track',
|
|
||||||
disabledInputRange: 'disabled-range',
|
|
||||||
inputRange: 'input-range',
|
|
||||||
labelContainer: 'label-container',
|
|
||||||
maxLabel: 'max',
|
|
||||||
minLabel: 'min',
|
|
||||||
sliderContainer: 'slider-container',
|
|
||||||
track: 'track',
|
|
||||||
valueLabel: 'value',
|
|
||||||
slider: 'slider'
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Slider;
|
export default Slider;
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
import { css } from 'styled-components';
|
|
||||||
import remcalc from 'remcalc';
|
|
||||||
|
|
||||||
import theme from '../theme';
|
|
||||||
|
|
||||||
export const sliderStyles = css`
|
|
||||||
appearance: none;
|
|
||||||
background: ${theme.white};
|
|
||||||
border: 2px solid ${theme.greyLight};
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
height: ${remcalc(14)};
|
|
||||||
width: ${remcalc(14)};
|
|
||||||
transform: translateY(-50%) translateX(-50%);
|
|
||||||
outline: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: ${remcalc(2)};
|
|
||||||
|
|
||||||
&::active {
|
|
||||||
transform: scale(1.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::focus {
|
|
||||||
box-shadow: 0 0 0 5px rgba(63, 81, 181, 0.2);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const disabledStyles = css`
|
|
||||||
.track {
|
|
||||||
background: ${theme.grey};
|
|
||||||
}
|
|
||||||
.slider {
|
|
||||||
background: ${theme.greyDark};
|
|
||||||
border: 1px solid ${theme.greyDark};
|
|
||||||
box-shadow: none;
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const trackStyles = css`
|
|
||||||
background: ${theme.grey};
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
height: ${remcalc(4)};
|
|
||||||
position: relative;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const activeStyles = css`
|
|
||||||
background: ${theme.blue};
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const rangeStyles = css`
|
|
||||||
position: relative;
|
|
||||||
width: calc(100% - 18px);
|
|
||||||
margin: auto;
|
|
||||||
min-height: ${remcalc(10)};
|
|
||||||
`;
|
|
3
packages/ui-toolkit/src/slider/react-input-range/index.js
vendored
Executable file
3
packages/ui-toolkit/src/slider/react-input-range/index.js
vendored
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
import InputRange from './input-range/input-range';
|
||||||
|
|
||||||
|
export default InputRange;
|
725
packages/ui-toolkit/src/slider/react-input-range/input-range/input-range.jsx
Executable file
725
packages/ui-toolkit/src/slider/react-input-range/input-range/input-range.jsx
Executable file
@ -0,0 +1,725 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import * as valueTransformer from './value-transformer';
|
||||||
|
import rangePropType from './range-prop-type';
|
||||||
|
import valuePropType from './value-prop-type';
|
||||||
|
import Slider from './slider';
|
||||||
|
import Track from './track';
|
||||||
|
import { captialize, distanceTo, isDefined, isObject, length } from '../utils';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import remcalc from 'remcalc';
|
||||||
|
|
||||||
|
export const RangeStyled = styled.div`
|
||||||
|
position: relative;
|
||||||
|
min-height: ${remcalc(10)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A React component that allows users to input numeric values within a range
|
||||||
|
* by dragging its sliders.
|
||||||
|
*/
|
||||||
|
export default class InputRange extends Component {
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @override
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
static get propTypes() {
|
||||||
|
return {
|
||||||
|
ariaLabelledby: PropTypes.string,
|
||||||
|
ariaControls: PropTypes.string,
|
||||||
|
classNames: PropTypes.objectOf(PropTypes.string),
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
draggableTrack: PropTypes.bool,
|
||||||
|
formatLabel: PropTypes.func,
|
||||||
|
maxValue: rangePropType,
|
||||||
|
minValue: rangePropType,
|
||||||
|
name: PropTypes.string,
|
||||||
|
onChangeStart: PropTypes.func,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
onChangeComplete: PropTypes.func,
|
||||||
|
step: PropTypes.number,
|
||||||
|
value: valuePropType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @override
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
static get defaultProps() {
|
||||||
|
return {
|
||||||
|
disabled: false,
|
||||||
|
maxValue: 10,
|
||||||
|
minValue: 0,
|
||||||
|
step: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} props
|
||||||
|
* @param {string} [props.ariaLabelledby]
|
||||||
|
* @param {string} [props.ariaControls]
|
||||||
|
* @param {InputRangeClassNames} [props.classNames]
|
||||||
|
* @param {boolean} [props.disabled = false]
|
||||||
|
* @param {Function} [props.formatLabel]
|
||||||
|
* @param {number|Range} [props.maxValue = 10]
|
||||||
|
* @param {number|Range} [props.minValue = 0]
|
||||||
|
* @param {string} [props.name]
|
||||||
|
* @param {string} props.onChange
|
||||||
|
* @param {Function} [props.onChangeComplete]
|
||||||
|
* @param {Function} [props.onChangeStart]
|
||||||
|
* @param {number} [props.step = 1]
|
||||||
|
* @param {number|Range} props.value
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {?number}
|
||||||
|
*/
|
||||||
|
this.startValue = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {?Component}
|
||||||
|
*/
|
||||||
|
this.node = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {?Component}
|
||||||
|
*/
|
||||||
|
this.trackNode = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {bool}
|
||||||
|
*/
|
||||||
|
this.isSliderDragging = false;
|
||||||
|
|
||||||
|
this.handleSliderDrag = this.handleSliderDrag.bind(this);
|
||||||
|
this.handleTrackDrag = this.handleTrackDrag.bind(this);
|
||||||
|
this.handleTrackMouseDown = this.handleTrackMouseDown.bind(this);
|
||||||
|
this.handleInteractionStart = this.handleInteractionStart.bind(this);
|
||||||
|
this.handleInteractionEnd = this.handleInteractionEnd.bind(this);
|
||||||
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
|
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||||
|
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||||
|
this.handleKeyUp = this.handleKeyUp.bind(this);
|
||||||
|
this.handleTouchStart = this.handleTouchStart.bind(this);
|
||||||
|
this.handleTouchEnd = this.handleTouchEnd.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @override
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
this.removeDocumentTouchEndListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the bounding rect of the track
|
||||||
|
* @private
|
||||||
|
* @return {ClientRect}
|
||||||
|
*/
|
||||||
|
getTrackClientRect() {
|
||||||
|
return this.trackNode.getClientRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the slider key closest to a point
|
||||||
|
* @private
|
||||||
|
* @param {Point} position
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
getKeyByPosition(position) {
|
||||||
|
const values = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
const positions = valueTransformer.getPositionsFromValues(
|
||||||
|
values,
|
||||||
|
this.props.minValue,
|
||||||
|
this.props.maxValue,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.isMultiValue()) {
|
||||||
|
const distanceToMin = distanceTo(position, positions.min);
|
||||||
|
const distanceToMax = distanceTo(position, positions.max);
|
||||||
|
|
||||||
|
if (distanceToMin < distanceToMax) {
|
||||||
|
return 'min';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'max';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all the slider keys
|
||||||
|
* @private
|
||||||
|
* @return {string[]}
|
||||||
|
*/
|
||||||
|
getKeys() {
|
||||||
|
if (this.isMultiValue()) {
|
||||||
|
return ['min', 'max'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['max'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the difference between the new and the current value is
|
||||||
|
* greater or equal to the step amount of the component
|
||||||
|
* @private
|
||||||
|
* @param {Range} values
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
hasStepDifference(values) {
|
||||||
|
const currentValues = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
length(values.min, currentValues.min) >= this.props.step ||
|
||||||
|
length(values.max, currentValues.max) >= this.props.step
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the component accepts a min and max value
|
||||||
|
* @private
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
isMultiValue() {
|
||||||
|
return isObject(this.props.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the range is within the max and min value of the component
|
||||||
|
* @private
|
||||||
|
* @param {Range} values
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
isWithinRange(values) {
|
||||||
|
if (this.isMultiValue()) {
|
||||||
|
return (
|
||||||
|
values.min >= this.props.minValue &&
|
||||||
|
values.max <= this.props.maxValue &&
|
||||||
|
values.min < values.max
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
values.max >= this.props.minValue && values.max <= this.props.maxValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the new value should trigger a render
|
||||||
|
* @private
|
||||||
|
* @param {Range} values
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
shouldUpdate(values) {
|
||||||
|
return this.isWithinRange(values) && this.hasStepDifference(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the position of a slider
|
||||||
|
* @private
|
||||||
|
* @param {string} key
|
||||||
|
* @param {Point} position
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
updatePosition(key, position) {
|
||||||
|
const values = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
const positions = valueTransformer.getPositionsFromValues(
|
||||||
|
values,
|
||||||
|
this.props.minValue,
|
||||||
|
this.props.maxValue,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
|
||||||
|
positions[key] = position;
|
||||||
|
|
||||||
|
this.updatePositions(positions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the positions of multiple sliders
|
||||||
|
* @private
|
||||||
|
* @param {Object} positions
|
||||||
|
* @param {Point} positions.min
|
||||||
|
* @param {Point} positions.max
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
updatePositions(positions) {
|
||||||
|
const values = {
|
||||||
|
min: valueTransformer.getValueFromPosition(
|
||||||
|
positions.min,
|
||||||
|
this.props.minValue,
|
||||||
|
this.props.maxValue,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
),
|
||||||
|
max: valueTransformer.getValueFromPosition(
|
||||||
|
positions.max,
|
||||||
|
this.props.minValue,
|
||||||
|
this.props.maxValue,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformedValues = {
|
||||||
|
min: valueTransformer.getStepValueFromValue(values.min, this.props.step),
|
||||||
|
max: valueTransformer.getStepValueFromValue(values.max, this.props.step)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.updateValues(transformedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the value of a slider
|
||||||
|
* @private
|
||||||
|
* @param {string} key
|
||||||
|
* @param {number} value
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
updateValue(key, value) {
|
||||||
|
const values = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
|
||||||
|
values[key] = value;
|
||||||
|
|
||||||
|
this.updateValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the values of multiple sliders
|
||||||
|
* @private
|
||||||
|
* @param {Range|number} values
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
updateValues(values) {
|
||||||
|
if (!this.shouldUpdate(values)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onChange(this.isMultiValue() ? values : values.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the value of a slider by key name
|
||||||
|
* @private
|
||||||
|
* @param {string} key
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
incrementValue(key) {
|
||||||
|
const values = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
const value = values[key] + this.props.step;
|
||||||
|
|
||||||
|
this.updateValue(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement the value of a slider by key name
|
||||||
|
* @private
|
||||||
|
* @param {string} key
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
decrementValue(key) {
|
||||||
|
const values = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
const value = values[key] - this.props.step;
|
||||||
|
|
||||||
|
this.updateValue(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to mouseup event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentMouseUpListener() {
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
this.node.ownerDocument.addEventListener('mouseup', this.handleMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to touchend event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentTouchEndListener() {
|
||||||
|
this.removeDocumentTouchEndListener();
|
||||||
|
this.node.ownerDocument.addEventListener('touchend', this.handleTouchEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop listening to mouseup event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentMouseUpListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener('mouseup', this.handleMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop listening to touchend event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentTouchEndListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener(
|
||||||
|
'touchend',
|
||||||
|
this.handleTouchEnd
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "mousemove" event received by the slider
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @param {string} key
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleSliderDrag(event, key) {
|
||||||
|
if (this.props.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const position = valueTransformer.getPositionFromEvent(
|
||||||
|
event,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
this.isSliderDragging = true;
|
||||||
|
requestAnimationFrame(() => this.updatePosition(key, position));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "mousemove" event received by the track
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleTrackDrag(event, prevEvent) {
|
||||||
|
if (
|
||||||
|
this.props.disabled ||
|
||||||
|
!this.props.draggableTrack ||
|
||||||
|
this.isSliderDragging
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { maxValue, minValue, value: { max, min } } = this.props;
|
||||||
|
|
||||||
|
const position = valueTransformer.getPositionFromEvent(
|
||||||
|
event,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
const value = valueTransformer.getValueFromPosition(
|
||||||
|
position,
|
||||||
|
minValue,
|
||||||
|
maxValue,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
const stepValue = valueTransformer.getStepValueFromValue(
|
||||||
|
value,
|
||||||
|
this.props.step
|
||||||
|
);
|
||||||
|
|
||||||
|
const prevPosition = valueTransformer.getPositionFromEvent(
|
||||||
|
prevEvent,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
const prevValue = valueTransformer.getValueFromPosition(
|
||||||
|
prevPosition,
|
||||||
|
minValue,
|
||||||
|
maxValue,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
const prevStepValue = valueTransformer.getStepValueFromValue(
|
||||||
|
prevValue,
|
||||||
|
this.props.step
|
||||||
|
);
|
||||||
|
|
||||||
|
const offset = prevStepValue - stepValue;
|
||||||
|
|
||||||
|
const transformedValues = {
|
||||||
|
min: min - offset,
|
||||||
|
max: max - offset
|
||||||
|
};
|
||||||
|
|
||||||
|
this.updateValues(transformedValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "mousedown" event received by the track
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @param {Point} position
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
handleTrackMouseDown(event, position) {
|
||||||
|
if (this.props.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { maxValue, minValue, value: { max, min } } = this.props;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const value = valueTransformer.getValueFromPosition(
|
||||||
|
position,
|
||||||
|
minValue,
|
||||||
|
maxValue,
|
||||||
|
this.getTrackClientRect()
|
||||||
|
);
|
||||||
|
const stepValue = valueTransformer.getStepValueFromValue(
|
||||||
|
value,
|
||||||
|
this.props.step
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!this.props.draggableTrack || stepValue > max || stepValue < min) {
|
||||||
|
this.updatePosition(this.getKeyByPosition(position), position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the start of any mouse/touch event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
handleInteractionStart() {
|
||||||
|
if (this.props.onChangeStart) {
|
||||||
|
this.props.onChangeStart(this.props.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.onChangeComplete && !isDefined(this.startValue)) {
|
||||||
|
this.startValue = this.props.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the end of any mouse/touch event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleInteractionEnd() {
|
||||||
|
if (this.isSliderDragging) {
|
||||||
|
this.isSliderDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.props.onChangeComplete || !isDefined(this.startValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.startValue !== this.props.value) {
|
||||||
|
this.props.onChangeComplete(this.props.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "keydown" event received by the component
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
handleKeyDown(event) {
|
||||||
|
this.handleInteractionStart(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "keyup" event received by the component
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleKeyUp(event) {
|
||||||
|
this.handleInteractionEnd(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "mousedown" event received by the component
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
handleMouseDown(event) {
|
||||||
|
this.handleInteractionStart(event);
|
||||||
|
this.addDocumentMouseUpListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "mouseup" event received by the component
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
*/
|
||||||
|
|
||||||
|
handleMouseUp(event) {
|
||||||
|
this.handleInteractionEnd(event);
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "touchstart" event received by the component
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
handleTouchStart(event) {
|
||||||
|
this.handleInteractionStart(event);
|
||||||
|
this.addDocumentTouchEndListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle any "touchend" event received by the component
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
*/
|
||||||
|
handleTouchEnd(event) {
|
||||||
|
this.handleInteractionEnd(event);
|
||||||
|
this.removeDocumentTouchEndListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return JSX of sliders
|
||||||
|
* @private
|
||||||
|
* @return {JSX.Element}
|
||||||
|
*/
|
||||||
|
renderSliders() {
|
||||||
|
const values = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
const percentages = valueTransformer.getPercentagesFromValues(
|
||||||
|
values,
|
||||||
|
this.props.minValue,
|
||||||
|
this.props.maxValue
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.getKeys().map(key => {
|
||||||
|
const value = values[key];
|
||||||
|
const percentage = percentages[key];
|
||||||
|
|
||||||
|
let { maxValue, minValue } = this.props;
|
||||||
|
|
||||||
|
if (key === 'min') {
|
||||||
|
maxValue = values.max;
|
||||||
|
} else {
|
||||||
|
minValue = values.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
const slider = (
|
||||||
|
<Slider
|
||||||
|
ariaLabelledby={this.props.ariaLabelledby}
|
||||||
|
ariaControls={this.props.ariaControls}
|
||||||
|
classNames={this.props.classNames}
|
||||||
|
formatLabel={this.props.formatLabel}
|
||||||
|
key={key}
|
||||||
|
maxValue={maxValue}
|
||||||
|
minValue={minValue}
|
||||||
|
onSliderDrag={this.handleSliderDrag}
|
||||||
|
percentage={percentage}
|
||||||
|
type={key}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return slider;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return JSX of hidden inputs
|
||||||
|
* @private
|
||||||
|
* @return {JSX.Element}
|
||||||
|
*/
|
||||||
|
renderHiddenInputs() {
|
||||||
|
if (!this.props.name) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMultiValue = this.isMultiValue();
|
||||||
|
const values = valueTransformer.getValueFromProps(this.props, isMultiValue);
|
||||||
|
|
||||||
|
return this.getKeys().map(key => {
|
||||||
|
const value = values[key];
|
||||||
|
const name = isMultiValue
|
||||||
|
? `${this.props.name}${captialize(key)}`
|
||||||
|
: this.props.name;
|
||||||
|
|
||||||
|
return <input key={key} type="hidden" name={name} value={value} />;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @override
|
||||||
|
* @return {JSX.Element}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const values = valueTransformer.getValueFromProps(
|
||||||
|
this.props,
|
||||||
|
this.isMultiValue()
|
||||||
|
);
|
||||||
|
const percentages = valueTransformer.getPercentagesFromValues(
|
||||||
|
values,
|
||||||
|
this.props.minValue,
|
||||||
|
this.props.maxValue
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RangeStyled
|
||||||
|
aria-disabled={this.props.disabled}
|
||||||
|
ref={node => {
|
||||||
|
this.node = node;
|
||||||
|
}}
|
||||||
|
onKeyDown={this.handleKeyDown}
|
||||||
|
onKeyUp={this.handleKeyUp}
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
onTouchStart={this.handleTouchStart}
|
||||||
|
>
|
||||||
|
<Track
|
||||||
|
classNames={this.props.classNames}
|
||||||
|
draggableTrack={this.props.draggableTrack}
|
||||||
|
ref={trackNode => {
|
||||||
|
this.trackNode = trackNode;
|
||||||
|
}}
|
||||||
|
percentages={percentages}
|
||||||
|
onTrackDrag={this.handleTrackDrag}
|
||||||
|
onTrackMouseDown={this.handleTrackMouseDown}
|
||||||
|
>
|
||||||
|
{this.renderSliders()}
|
||||||
|
</Track>
|
||||||
|
|
||||||
|
{this.renderHiddenInputs()}
|
||||||
|
</RangeStyled>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
44
packages/ui-toolkit/src/slider/react-input-range/input-range/label.jsx
Executable file
44
packages/ui-toolkit/src/slider/react-input-range/input-range/label.jsx
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import remcalc from 'remcalc';
|
||||||
|
|
||||||
|
import theme from '../../../theme';
|
||||||
|
|
||||||
|
const Span = styled.span`
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: ${remcalc(10)};
|
||||||
|
color: ${theme.secondary};
|
||||||
|
position: absolute;
|
||||||
|
top: ${remcalc(8)};
|
||||||
|
right: ${props => (props.type === 'max' ? '1px' : 'auto')};
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @param {Object} props
|
||||||
|
* @param {InputRangeClassNames} props.classNames
|
||||||
|
* @param {Function} props.formatLabel
|
||||||
|
* @param {string} props.type
|
||||||
|
*/
|
||||||
|
export default function Label(props) {
|
||||||
|
const labelValue = props.formatLabel
|
||||||
|
? props.formatLabel(props.children, props.type)
|
||||||
|
: props.children;
|
||||||
|
|
||||||
|
return <Span type={props.type}>{labelValue}</Span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
* @property {Function} children
|
||||||
|
* @property {Function} classNames
|
||||||
|
* @property {Function} formatLabel
|
||||||
|
* @property {Function} type
|
||||||
|
*/
|
||||||
|
Label.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
classNames: PropTypes.objectOf(PropTypes.string).isRequired,
|
||||||
|
formatLabel: PropTypes.func,
|
||||||
|
type: PropTypes.string.isRequired
|
||||||
|
};
|
18
packages/ui-toolkit/src/slider/react-input-range/input-range/range-prop-type.js
vendored
Executable file
18
packages/ui-toolkit/src/slider/react-input-range/input-range/range-prop-type.js
vendored
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
import { isNumber } from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @param {Object} props - React component props
|
||||||
|
* @return {?Error} Return Error if validation fails
|
||||||
|
*/
|
||||||
|
export default function rangePropType(props) {
|
||||||
|
const { maxValue, minValue } = props;
|
||||||
|
|
||||||
|
if (!isNumber(minValue) || !isNumber(maxValue)) {
|
||||||
|
return new Error('"minValue" and "maxValue" must be a number');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minValue >= maxValue) {
|
||||||
|
return new Error('"minValue" must be smaller than "maxValue"');
|
||||||
|
}
|
||||||
|
}
|
309
packages/ui-toolkit/src/slider/react-input-range/input-range/slider.jsx
Executable file
309
packages/ui-toolkit/src/slider/react-input-range/input-range/slider.jsx
Executable file
@ -0,0 +1,309 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Label from './label';
|
||||||
|
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import remcalc from 'remcalc';
|
||||||
|
import theme from '../../../theme';
|
||||||
|
|
||||||
|
export const SliderStyled = styled.div`
|
||||||
|
appearance: none;
|
||||||
|
background: ${theme.white};
|
||||||
|
border: 2px solid ${theme.greyLight};
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
height: ${remcalc(14)};
|
||||||
|
width: ${remcalc(14)};
|
||||||
|
transform: ${props =>
|
||||||
|
props.type === 'max'
|
||||||
|
? 'translateY(-50%) translateX(-99%)'
|
||||||
|
: 'translateY(-50%) translateX(-1%)'};
|
||||||
|
outline: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
margin-top: ${remcalc(2)};
|
||||||
|
|
||||||
|
&::active {
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::focus {
|
||||||
|
box-shadow: 0 0 0 5px rgba(63, 81, 181, 0.2);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
export default class Slider extends Component {
|
||||||
|
/**
|
||||||
|
* Accepted propTypes of Slider
|
||||||
|
* @override
|
||||||
|
* @return {Object}
|
||||||
|
* @property {Function} ariaLabelledby
|
||||||
|
* @property {Function} ariaControls
|
||||||
|
* @property {Function} className
|
||||||
|
* @property {Function} formatLabel
|
||||||
|
* @property {Function} maxValue
|
||||||
|
* @property {Function} minValue
|
||||||
|
* @property {Function} onSliderDrag
|
||||||
|
* @property {Function} onSliderKeyDown
|
||||||
|
* @property {Function} percentage
|
||||||
|
* @property {Function} type
|
||||||
|
* @property {Function} value
|
||||||
|
*/
|
||||||
|
static get propTypes() {
|
||||||
|
return {
|
||||||
|
ariaLabelledby: PropTypes.string,
|
||||||
|
ariaControls: PropTypes.string,
|
||||||
|
classNames: PropTypes.objectOf(PropTypes.string).isRequired,
|
||||||
|
formatLabel: PropTypes.func,
|
||||||
|
maxValue: PropTypes.number,
|
||||||
|
minValue: PropTypes.number,
|
||||||
|
onSliderDrag: PropTypes.func.isRequired,
|
||||||
|
onSliderKeyDown: PropTypes.func.isRequired,
|
||||||
|
percentage: PropTypes.number.isRequired,
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
value: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} props
|
||||||
|
* @param {string} [props.ariaLabelledby]
|
||||||
|
* @param {string} [props.ariaControls]
|
||||||
|
* @param {InputRangeClassNames} props.classNames
|
||||||
|
* @param {Function} [props.formatLabel]
|
||||||
|
* @param {number} [props.maxValue]
|
||||||
|
* @param {number} [props.minValue]
|
||||||
|
* @param {Function} props.onSliderKeyDown
|
||||||
|
* @param {Function} props.onSliderDrag
|
||||||
|
* @param {number} props.percentage
|
||||||
|
* @param {number} props.type
|
||||||
|
* @param {number} props.value
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {?Component}
|
||||||
|
*/
|
||||||
|
this.node = null;
|
||||||
|
|
||||||
|
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||||
|
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||||
|
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||||
|
this.handleTouchStart = this.handleTouchStart.bind(this);
|
||||||
|
this.handleTouchMove = this.handleTouchMove.bind(this);
|
||||||
|
this.handleTouchEnd = this.handleTouchEnd.bind(this);
|
||||||
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @override
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.removeDocumentMouseMoveListener();
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
this.removeDocumentTouchEndListener();
|
||||||
|
this.removeDocumentTouchMoveListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
getStyle() {
|
||||||
|
const perc = (this.props.percentage || 0) * 100;
|
||||||
|
const style = {
|
||||||
|
position: 'absolute',
|
||||||
|
left: `${perc}%`
|
||||||
|
};
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to mousemove event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentMouseMoveListener() {
|
||||||
|
this.removeDocumentMouseMoveListener();
|
||||||
|
this.node.ownerDocument.addEventListener('mousemove', this.handleMouseMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to mouseup event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentMouseUpListener() {
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
this.node.ownerDocument.addEventListener('mouseup', this.handleMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to touchmove event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentTouchMoveListener() {
|
||||||
|
this.removeDocumentTouchMoveListener();
|
||||||
|
this.node.ownerDocument.addEventListener('touchmove', this.handleTouchMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to touchend event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentTouchEndListener() {
|
||||||
|
this.removeDocumentTouchEndListener();
|
||||||
|
this.node.ownerDocument.addEventListener('touchend', this.handleTouchEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentMouseMoveListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener(
|
||||||
|
'mousemove',
|
||||||
|
this.handleMouseMove
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentMouseUpListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener('mouseup', this.handleMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentTouchMoveListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener(
|
||||||
|
'touchmove',
|
||||||
|
this.handleTouchMove
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentTouchEndListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener(
|
||||||
|
'touchend',
|
||||||
|
this.handleTouchEnd
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleMouseDown() {
|
||||||
|
this.addDocumentMouseMoveListener();
|
||||||
|
this.addDocumentMouseUpListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleMouseUp() {
|
||||||
|
this.removeDocumentMouseMoveListener();
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleMouseMove(event) {
|
||||||
|
this.props.onSliderDrag(event, this.props.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleTouchStart() {
|
||||||
|
this.addDocumentTouchEndListener();
|
||||||
|
this.addDocumentTouchMoveListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleTouchMove(event) {
|
||||||
|
this.props.onSliderDrag(event, this.props.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleTouchEnd() {
|
||||||
|
this.removeDocumentTouchMoveListener();
|
||||||
|
this.removeDocumentTouchEndListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleKeyDown(event) {
|
||||||
|
this.props.onSliderKeyDown(event, this.props.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @return {JSX.Element}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const style = this.getStyle();
|
||||||
|
const props = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
ref={node => {
|
||||||
|
this.node = node;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Label formatLabel={props.formatLabel} type={props.type}>
|
||||||
|
{props.value}
|
||||||
|
</Label>
|
||||||
|
<SliderStyled
|
||||||
|
type={props.type}
|
||||||
|
style={style}
|
||||||
|
aria-labelledby={props.ariaLabelledby}
|
||||||
|
aria-controls={props.ariaControls}
|
||||||
|
aria-valuemax={props.maxValue}
|
||||||
|
aria-valuemin={props.minValue}
|
||||||
|
aria-valuenow={props.value}
|
||||||
|
draggable="false"
|
||||||
|
onKeyDown={this.handleKeyDown}
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
onTouchStart={this.handleTouchStart}
|
||||||
|
role="slider"
|
||||||
|
tabIndex="0"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
210
packages/ui-toolkit/src/slider/react-input-range/input-range/track.jsx
Executable file
210
packages/ui-toolkit/src/slider/react-input-range/input-range/track.jsx
Executable file
@ -0,0 +1,210 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import remcalc from 'remcalc';
|
||||||
|
import theme from '../../../theme';
|
||||||
|
|
||||||
|
export const TrackStyled = styled.div`
|
||||||
|
background: ${theme.grey};
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
height: ${remcalc(4)};
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ActiveTrack = styled.div`
|
||||||
|
background: ${theme.blue};
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
export default class Track extends Component {
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @return {Object}
|
||||||
|
* @property {Function} children
|
||||||
|
* @property {Function} classNames
|
||||||
|
* @property {Boolean} draggableTrack
|
||||||
|
* @property {Function} onTrackDrag
|
||||||
|
* @property {Function} onTrackMouseDown
|
||||||
|
* @property {Function} percentages
|
||||||
|
*/
|
||||||
|
static get propTypes() {
|
||||||
|
return {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
classNames: PropTypes.objectOf(PropTypes.string).isRequired,
|
||||||
|
draggableTrack: PropTypes.bool,
|
||||||
|
onTrackDrag: PropTypes.func,
|
||||||
|
onTrackMouseDown: PropTypes.func.isRequired,
|
||||||
|
percentages: PropTypes.objectOf(PropTypes.number).isRequired
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} props
|
||||||
|
* @param {InputRangeClassNames} props.classNames
|
||||||
|
* @param {Boolean} props.draggableTrack
|
||||||
|
* @param {Function} props.onTrackDrag
|
||||||
|
* @param {Function} props.onTrackMouseDown
|
||||||
|
* @param {number} props.percentages
|
||||||
|
*/
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {?Component}
|
||||||
|
*/
|
||||||
|
this.node = null;
|
||||||
|
this.trackDragEvent = null;
|
||||||
|
|
||||||
|
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||||
|
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||||
|
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||||
|
this.handleTouchStart = this.handleTouchStart.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {ClientRect}
|
||||||
|
*/
|
||||||
|
getClientRect() {
|
||||||
|
return this.node.getBoundingClientRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {Object} CSS styles
|
||||||
|
*/
|
||||||
|
getActiveTrackStyle() {
|
||||||
|
const width = `${(this.props.percentages.max - this.props.percentages.min) *
|
||||||
|
100}%`;
|
||||||
|
const left = `${this.props.percentages.min * 100}%`;
|
||||||
|
|
||||||
|
return { left, width };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to mousemove event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentMouseMoveListener() {
|
||||||
|
this.removeDocumentMouseMoveListener();
|
||||||
|
this.node.ownerDocument.addEventListener('mousemove', this.handleMouseMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to mouseup event
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
addDocumentMouseUpListener() {
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
this.node.ownerDocument.addEventListener('mouseup', this.handleMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentMouseMoveListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener(
|
||||||
|
'mousemove',
|
||||||
|
this.handleMouseMove
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
removeDocumentMouseUpListener() {
|
||||||
|
this.node.ownerDocument.removeEventListener('mouseup', this.handleMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleMouseMove(event) {
|
||||||
|
if (!this.props.draggableTrack) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.trackDragEvent !== null) {
|
||||||
|
this.props.onTrackDrag(event, this.trackDragEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.trackDragEvent = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
handleMouseUp() {
|
||||||
|
if (!this.props.draggableTrack) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeDocumentMouseMoveListener();
|
||||||
|
this.removeDocumentMouseUpListener();
|
||||||
|
this.trackDragEvent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event - User event
|
||||||
|
*/
|
||||||
|
handleMouseDown(event) {
|
||||||
|
const clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
||||||
|
const trackClientRect = this.getClientRect();
|
||||||
|
const position = {
|
||||||
|
x: clientX - trackClientRect.left,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.props.onTrackMouseDown(event, position);
|
||||||
|
|
||||||
|
if (this.props.draggableTrack) {
|
||||||
|
this.addDocumentMouseMoveListener();
|
||||||
|
this.addDocumentMouseUpListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {SyntheticEvent} event - User event
|
||||||
|
*/
|
||||||
|
handleTouchStart(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.handleMouseDown(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @return {JSX.Element}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const activeTrackStyle = this.getActiveTrackStyle();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TrackStyled
|
||||||
|
onMouseDown={this.handleMouseDown}
|
||||||
|
onTouchStart={this.handleTouchStart}
|
||||||
|
innerRef={node => {
|
||||||
|
this.node = node;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ActiveTrack style={activeTrackStyle} />
|
||||||
|
{this.props.children}
|
||||||
|
</TrackStyled>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
23
packages/ui-toolkit/src/slider/react-input-range/input-range/value-prop-type.js
vendored
Executable file
23
packages/ui-toolkit/src/slider/react-input-range/input-range/value-prop-type.js
vendored
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
import { isNumber, isObject } from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
* @param {Object} props
|
||||||
|
* @return {?Error} Return Error if validation fails
|
||||||
|
*/
|
||||||
|
export default function valuePropType(props, propName) {
|
||||||
|
const { maxValue, minValue } = props;
|
||||||
|
const value = props[propName];
|
||||||
|
|
||||||
|
if (!isNumber(value) && (!isObject(value) || !isNumber(value.min) || !isNumber(value.max))) {
|
||||||
|
return new Error(`"${propName}" must be a number or a range object`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(value) && (value < minValue || value > maxValue)) {
|
||||||
|
return new Error(`"${propName}" must be in between "minValue" and "maxValue"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isObject(value) && (value.min < minValue || value.min > maxValue || value.max < minValue || value.max > maxValue)) {
|
||||||
|
return new Error(`"${propName}" must be in between "minValue" and "maxValue"`);
|
||||||
|
}
|
||||||
|
}
|
144
packages/ui-toolkit/src/slider/react-input-range/input-range/value-transformer.js
vendored
Executable file
144
packages/ui-toolkit/src/slider/react-input-range/input-range/value-transformer.js
vendored
Executable file
@ -0,0 +1,144 @@
|
|||||||
|
import { clamp } from '../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a point into a percentage value
|
||||||
|
* @ignore
|
||||||
|
* @param {Point} position
|
||||||
|
* @param {ClientRect} clientRect
|
||||||
|
* @return {number} Percentage value
|
||||||
|
*/
|
||||||
|
export function getPercentageFromPosition(position, clientRect) {
|
||||||
|
const length = clientRect.width;
|
||||||
|
const sizePerc = position.x / length;
|
||||||
|
|
||||||
|
return sizePerc || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a point into a model value
|
||||||
|
* @ignore
|
||||||
|
* @param {Point} position
|
||||||
|
* @param {number} minValue
|
||||||
|
* @param {number} maxValue
|
||||||
|
* @param {ClientRect} clientRect
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
export function getValueFromPosition(position, minValue, maxValue, clientRect) {
|
||||||
|
const sizePerc = getPercentageFromPosition(position, clientRect);
|
||||||
|
const valueDiff = maxValue - minValue;
|
||||||
|
|
||||||
|
return minValue + (valueDiff * sizePerc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert props into a range value
|
||||||
|
* @ignore
|
||||||
|
* @param {Object} props
|
||||||
|
* @param {boolean} isMultiValue
|
||||||
|
* @return {Range}
|
||||||
|
*/
|
||||||
|
export function getValueFromProps(props, isMultiValue) {
|
||||||
|
if (isMultiValue) {
|
||||||
|
return { ...props.value };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
min: props.minValue,
|
||||||
|
max: props.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a model value into a percentage value
|
||||||
|
* @ignore
|
||||||
|
* @param {number} value
|
||||||
|
* @param {number} minValue
|
||||||
|
* @param {number} maxValue
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
export function getPercentageFromValue(value, minValue, maxValue) {
|
||||||
|
const validValue = clamp(value, minValue, maxValue);
|
||||||
|
const valueDiff = maxValue - minValue;
|
||||||
|
const valuePerc = (validValue - minValue) / valueDiff;
|
||||||
|
|
||||||
|
return valuePerc || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert model values into percentage values
|
||||||
|
* @ignore
|
||||||
|
* @param {Range} values
|
||||||
|
* @param {number} minValue
|
||||||
|
* @param {number} maxValue
|
||||||
|
* @return {Range}
|
||||||
|
*/
|
||||||
|
export function getPercentagesFromValues(values, minValue, maxValue) {
|
||||||
|
return {
|
||||||
|
min: getPercentageFromValue(values.min, minValue, maxValue),
|
||||||
|
max: getPercentageFromValue(values.max, minValue, maxValue),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value into a point
|
||||||
|
* @ignore
|
||||||
|
* @param {number} value
|
||||||
|
* @param {number} minValue
|
||||||
|
* @param {number} maxValue
|
||||||
|
* @param {ClientRect} clientRect
|
||||||
|
* @return {Point} Position
|
||||||
|
*/
|
||||||
|
export function getPositionFromValue(value, minValue, maxValue, clientRect) {
|
||||||
|
const length = clientRect.width;
|
||||||
|
const valuePerc = getPercentageFromValue(value, minValue, maxValue);
|
||||||
|
const positionValue = valuePerc * length;
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: positionValue,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a range of values into points
|
||||||
|
* @ignore
|
||||||
|
* @param {Range} values
|
||||||
|
* @param {number} minValue
|
||||||
|
* @param {number} maxValue
|
||||||
|
* @param {ClientRect} clientRect
|
||||||
|
* @return {Range}
|
||||||
|
*/
|
||||||
|
export function getPositionsFromValues(values, minValue, maxValue, clientRect) {
|
||||||
|
return {
|
||||||
|
min: getPositionFromValue(values.min, minValue, maxValue, clientRect),
|
||||||
|
max: getPositionFromValue(values.max, minValue, maxValue, clientRect),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an event into a point
|
||||||
|
* @ignore
|
||||||
|
* @param {Event} event
|
||||||
|
* @param {ClientRect} clientRect
|
||||||
|
* @return {Point}
|
||||||
|
*/
|
||||||
|
export function getPositionFromEvent(event, clientRect) {
|
||||||
|
const length = clientRect.width;
|
||||||
|
const { clientX } = event.touches ? event.touches[0] : event;
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: clamp(clientX - clientRect.left, 0, length),
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a value into a step value
|
||||||
|
* @ignore
|
||||||
|
* @param {number} value
|
||||||
|
* @param {number} valuePerStep
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
export function getStepValueFromValue(value, valuePerStep) {
|
||||||
|
return Math.round(value / valuePerStep) * valuePerStep;
|
||||||
|
}
|
9
packages/ui-toolkit/src/slider/react-input-range/utils/captialize.js
vendored
Executable file
9
packages/ui-toolkit/src/slider/react-input-range/utils/captialize.js
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Captialize a string
|
||||||
|
* @ignore
|
||||||
|
* @param {string} string
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
export default function captialize(string) {
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
|
}
|
11
packages/ui-toolkit/src/slider/react-input-range/utils/clamp.js
vendored
Executable file
11
packages/ui-toolkit/src/slider/react-input-range/utils/clamp.js
vendored
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Clamp a value between a min and max value
|
||||||
|
* @ignore
|
||||||
|
* @param {number} value
|
||||||
|
* @param {number} min
|
||||||
|
* @param {number} max
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
export default function clamp(value, min, max) {
|
||||||
|
return Math.min(Math.max(value, min), max);
|
||||||
|
}
|
13
packages/ui-toolkit/src/slider/react-input-range/utils/distance-to.js
vendored
Executable file
13
packages/ui-toolkit/src/slider/react-input-range/utils/distance-to.js
vendored
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Calculate the distance between pointA and pointB
|
||||||
|
* @ignore
|
||||||
|
* @param {Point} pointA
|
||||||
|
* @param {Point} pointB
|
||||||
|
* @return {number} Distance
|
||||||
|
*/
|
||||||
|
export default function distanceTo(pointA, pointB) {
|
||||||
|
const xDiff = (pointB.x - pointA.x) ** 2;
|
||||||
|
const yDiff = (pointB.y - pointA.y) ** 2;
|
||||||
|
|
||||||
|
return Math.sqrt(xDiff + yDiff);
|
||||||
|
}
|
7
packages/ui-toolkit/src/slider/react-input-range/utils/index.js
vendored
Executable file
7
packages/ui-toolkit/src/slider/react-input-range/utils/index.js
vendored
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
export { default as captialize } from './captialize';
|
||||||
|
export { default as clamp } from './clamp';
|
||||||
|
export { default as distanceTo } from './distance-to';
|
||||||
|
export { default as isDefined } from './is-defined';
|
||||||
|
export { default as isNumber } from './is-number';
|
||||||
|
export { default as isObject } from './is-object';
|
||||||
|
export { default as length } from './length';
|
9
packages/ui-toolkit/src/slider/react-input-range/utils/is-defined.js
vendored
Executable file
9
packages/ui-toolkit/src/slider/react-input-range/utils/is-defined.js
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Check if a value is defined
|
||||||
|
* @ignore
|
||||||
|
* @param {*} value
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export default function isDefined(value) {
|
||||||
|
return value !== undefined && value !== null;
|
||||||
|
}
|
9
packages/ui-toolkit/src/slider/react-input-range/utils/is-number.js
vendored
Executable file
9
packages/ui-toolkit/src/slider/react-input-range/utils/is-number.js
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Check if a value is a number
|
||||||
|
* @ignore
|
||||||
|
* @param {*} value
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export default function isNumber(value) {
|
||||||
|
return typeof value === 'number';
|
||||||
|
}
|
9
packages/ui-toolkit/src/slider/react-input-range/utils/is-object.js
vendored
Executable file
9
packages/ui-toolkit/src/slider/react-input-range/utils/is-object.js
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Check if a value is an object
|
||||||
|
* @ignore
|
||||||
|
* @param {*} value
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export default function isObject(value) {
|
||||||
|
return value !== null && typeof value === 'object';
|
||||||
|
}
|
10
packages/ui-toolkit/src/slider/react-input-range/utils/length.js
vendored
Executable file
10
packages/ui-toolkit/src/slider/react-input-range/utils/length.js
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Calculate the absolute difference between two numbers
|
||||||
|
* @ignore
|
||||||
|
* @param {number} numA
|
||||||
|
* @param {number} numB
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
export default function length(numA, numB) {
|
||||||
|
return Math.abs(numA - numB);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user