feat: improved range slider
This commit is contained in:
parent
4c666bb438
commit
621f4c72f4
@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders <Filters /> without throwing 1`] = `
|
||||
.c6 {
|
||||
.c12 {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
@ -49,47 +49,47 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.c6::-moz-focus-inner,
|
||||
.c6[type='button']::-moz-focus-inner,
|
||||
.c6[type='reset']::-moz-focus-inner,
|
||||
.c6[type='submit']::-moz-focus-inner {
|
||||
.c12::-moz-focus-inner,
|
||||
.c12[type='button']::-moz-focus-inner,
|
||||
.c12[type='reset']::-moz-focus-inner,
|
||||
.c12[type='submit']::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.c6:-moz-focusring,
|
||||
.c6[type='button']:-moz-focusring,
|
||||
.c6[type='reset']:-moz-focusring,
|
||||
.c6[type='submit']:-moz-focusring {
|
||||
.c12:-moz-focusring,
|
||||
.c12[type='button']:-moz-focusring,
|
||||
.c12[type='reset']:-moz-focusring,
|
||||
.c12[type='submit']:-moz-focusring {
|
||||
outline: 0.0625rem dotted ButtonText;
|
||||
}
|
||||
|
||||
.c6:focus {
|
||||
.c12:focus {
|
||||
outline: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.c6:hover {
|
||||
.c12:hover {
|
||||
border: solid 0.0625rem;
|
||||
}
|
||||
|
||||
.c6:active,
|
||||
.c6:active:hover,
|
||||
.c6:active:focus {
|
||||
.c12:active,
|
||||
.c12:active:hover,
|
||||
.c12:active:focus {
|
||||
background-image: none;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.c6[disabled] {
|
||||
.c12[disabled] {
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.c6 + button {
|
||||
.c12 + button {
|
||||
margin-left: 1.25rem;
|
||||
}
|
||||
|
||||
.c7 {
|
||||
.c13 {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 1.15;
|
||||
@ -136,43 +136,43 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.c7::-moz-focus-inner,
|
||||
.c7[type='button']::-moz-focus-inner,
|
||||
.c7[type='reset']::-moz-focus-inner,
|
||||
.c7[type='submit']::-moz-focus-inner {
|
||||
.c13::-moz-focus-inner,
|
||||
.c13[type='button']::-moz-focus-inner,
|
||||
.c13[type='reset']::-moz-focus-inner,
|
||||
.c13[type='submit']::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.c7:-moz-focusring,
|
||||
.c7[type='button']:-moz-focusring,
|
||||
.c7[type='reset']:-moz-focusring,
|
||||
.c7[type='submit']:-moz-focusring {
|
||||
.c13:-moz-focusring,
|
||||
.c13[type='button']:-moz-focusring,
|
||||
.c13[type='reset']:-moz-focusring,
|
||||
.c13[type='submit']:-moz-focusring {
|
||||
outline: 0.0625rem dotted ButtonText;
|
||||
}
|
||||
|
||||
.c7:focus {
|
||||
.c13:focus {
|
||||
outline: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.c7:hover {
|
||||
.c13:hover {
|
||||
border: solid 0.0625rem;
|
||||
}
|
||||
|
||||
.c7:active,
|
||||
.c7:active:hover,
|
||||
.c7:active:focus {
|
||||
.c13:active,
|
||||
.c13:active:hover,
|
||||
.c13:active:focus {
|
||||
background-image: none;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.c7[disabled] {
|
||||
.c13[disabled] {
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.c7 + button {
|
||||
.c13 + button {
|
||||
margin-left: 1.25rem;
|
||||
}
|
||||
|
||||
@ -187,14 +187,25 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.c3 .input-range {
|
||||
position: relative;
|
||||
width: calc(100% - 18px);
|
||||
margin: auto;
|
||||
min-height: 0.625rem;
|
||||
.c7 {
|
||||
font-weight: 600;
|
||||
font-size: 0.625rem;
|
||||
color: #464646;
|
||||
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;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
@ -205,57 +216,56 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
display: block;
|
||||
height: 0.875rem;
|
||||
width: 0.875rem;
|
||||
-webkit-transform: translateY(-50%) translateX(-50%);
|
||||
-ms-transform: translateY(-50%) translateX(-50%);
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
-webkit-transform: translateY(-50%) translateX(-1%);
|
||||
-ms-transform: translateY(-50%) translateX(-1%);
|
||||
transform: translateY(-50%) translateX(-1%);
|
||||
outline: none;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
top: 0;
|
||||
margin-top: 0.125rem;
|
||||
}
|
||||
|
||||
.c3 .slider::active {
|
||||
.c8::active {
|
||||
-webkit-transform: scale(1.3);
|
||||
-ms-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);
|
||||
}
|
||||
|
||||
.c3 .disabled .track {
|
||||
background: #D8D8D8;
|
||||
}
|
||||
|
||||
.c3 .disabled .slider {
|
||||
background: #CCC;
|
||||
border: 1px solid #CCC;
|
||||
box-shadow: none;
|
||||
-webkit-transform: none;
|
||||
-ms-transform: none;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.c3 .min,
|
||||
.c3 .max {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.c3 .value {
|
||||
top: 0.5rem;
|
||||
.c10 {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background: #FFFFFF;
|
||||
border: 2px solid #bdbdbd;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 0.875rem;
|
||||
width: 0.875rem;
|
||||
-webkit-transform: translateY(-50%) translateX(-99%);
|
||||
-ms-transform: translateY(-50%) translateX(-99%);
|
||||
transform: translateY(-50%) translateX(-99%);
|
||||
outline: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
margin-top: 0.125rem;
|
||||
}
|
||||
|
||||
.c3 .value .label-container {
|
||||
font-weight: 600;
|
||||
font-size: 0.625rem;
|
||||
color: #464646;
|
||||
left: -50%;
|
||||
position: relative;
|
||||
.c10::active {
|
||||
-webkit-transform: scale(1.3);
|
||||
-ms-transform: scale(1.3);
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
.c3 .track {
|
||||
.c10::focus {
|
||||
box-shadow: 0 0 0 5px rgba(63,81,181,0.2);
|
||||
}
|
||||
|
||||
.c5 {
|
||||
background: #D8D8D8;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
@ -263,13 +273,18 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.c3 .active-track {
|
||||
.c6 {
|
||||
background: #364ACD;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
position: relative;
|
||||
min-height: 0.625rem;
|
||||
}
|
||||
|
||||
.c3 {
|
||||
margin-bottom: 0.625rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
@ -291,7 +306,7 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
margin-right: 2.25rem;
|
||||
}
|
||||
|
||||
.c5 {
|
||||
.c11 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
@ -320,39 +335,28 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
<section
|
||||
className="c2"
|
||||
>
|
||||
<div
|
||||
className="c3"
|
||||
>
|
||||
<div>
|
||||
<label
|
||||
className="c4 c1"
|
||||
className="c3 c1"
|
||||
htmlFor=""
|
||||
>
|
||||
GB RAM
|
||||
</label>
|
||||
<div
|
||||
aria-disabled={false}
|
||||
className="input-range"
|
||||
className="c4"
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<span
|
||||
className="min"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
0.256
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
className="track"
|
||||
className="c5"
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="active-track"
|
||||
className="c6"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
@ -360,117 +364,89 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
}
|
||||
}
|
||||
/>
|
||||
<span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c7"
|
||||
type="min"
|
||||
>
|
||||
0.256
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={50.688}
|
||||
aria-valuemin={0.256}
|
||||
aria-valuenow={0.256}
|
||||
className="slider"
|
||||
className="c8"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
tabIndex="0"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
tabIndex="0"
|
||||
type="min"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c9"
|
||||
type="max"
|
||||
>
|
||||
50.688
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={50.688}
|
||||
aria-valuemin={0.256}
|
||||
aria-valuenow={50.688}
|
||||
className="slider"
|
||||
className="c10"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
tabIndex="0"
|
||||
type="max"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className="max"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
50.688
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="c3"
|
||||
>
|
||||
<div>
|
||||
<label
|
||||
className="c4 c1"
|
||||
className="c3 c1"
|
||||
htmlFor=""
|
||||
>
|
||||
vCPUs
|
||||
</label>
|
||||
<div
|
||||
aria-disabled={false}
|
||||
className="input-range"
|
||||
className="c4"
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<span
|
||||
className="min"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
0.25
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
className="track"
|
||||
className="c5"
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="active-track"
|
||||
className="c6"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
@ -478,117 +454,89 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
}
|
||||
}
|
||||
/>
|
||||
<span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c7"
|
||||
type="min"
|
||||
>
|
||||
0.25
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={3.25}
|
||||
aria-valuemin={0.25}
|
||||
aria-valuenow={0.25}
|
||||
className="slider"
|
||||
className="c8"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
tabIndex="0"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
tabIndex="0"
|
||||
type="min"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c9"
|
||||
type="max"
|
||||
>
|
||||
3.25
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={3.25}
|
||||
aria-valuemin={0.25}
|
||||
aria-valuenow={3.25}
|
||||
className="slider"
|
||||
className="c10"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
tabIndex="0"
|
||||
type="max"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className="max"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
3.25
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="c3"
|
||||
>
|
||||
<div>
|
||||
<label
|
||||
className="c4 c1"
|
||||
className="c3 c1"
|
||||
htmlFor=""
|
||||
>
|
||||
TB Disk
|
||||
</label>
|
||||
<div
|
||||
aria-disabled={false}
|
||||
className="input-range"
|
||||
className="c4"
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<span
|
||||
className="min"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
0.01
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
className="track"
|
||||
className="c5"
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="active-track"
|
||||
className="c6"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
@ -596,117 +544,89 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
}
|
||||
}
|
||||
/>
|
||||
<span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c7"
|
||||
type="min"
|
||||
>
|
||||
0.01
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={107.26}
|
||||
aria-valuemin={0.01}
|
||||
aria-valuenow={0.01}
|
||||
className="slider"
|
||||
className="c8"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
tabIndex="0"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
tabIndex="0"
|
||||
type="min"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c9"
|
||||
type="max"
|
||||
>
|
||||
107.26
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={107.26}
|
||||
aria-valuemin={0.01}
|
||||
aria-valuenow={107.26}
|
||||
className="slider"
|
||||
className="c10"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
tabIndex="0"
|
||||
type="max"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className="max"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
107.26
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="c3"
|
||||
>
|
||||
<div>
|
||||
<label
|
||||
className="c4 c1"
|
||||
className="c3 c1"
|
||||
htmlFor=""
|
||||
>
|
||||
$/hr
|
||||
</label>
|
||||
<div
|
||||
aria-disabled={false}
|
||||
className="input-range"
|
||||
className="c4"
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<span
|
||||
className="min"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
0.016
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
className="track"
|
||||
className="c5"
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="active-track"
|
||||
className="c6"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
@ -714,112 +634,95 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
}
|
||||
}
|
||||
/>
|
||||
<span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c7"
|
||||
type="min"
|
||||
>
|
||||
0.016
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={0.525}
|
||||
aria-valuemin={0.016}
|
||||
aria-valuenow={0.016}
|
||||
className="slider"
|
||||
className="c8"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
tabIndex="0"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="slider-container"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"left": "0%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
>
|
||||
tabIndex="0"
|
||||
type="min"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
<span
|
||||
className="value"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
className="c9"
|
||||
type="max"
|
||||
>
|
||||
0.525
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
aria-controls={undefined}
|
||||
aria-labelledby={undefined}
|
||||
aria-valuemax={0.525}
|
||||
aria-valuemin={0.016}
|
||||
aria-valuenow={0.525}
|
||||
className="slider"
|
||||
className="c10"
|
||||
draggable="false"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
role="slider"
|
||||
style={
|
||||
Object {
|
||||
"left": "100%",
|
||||
"position": "absolute",
|
||||
}
|
||||
}
|
||||
tabIndex="0"
|
||||
type="max"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className="max"
|
||||
>
|
||||
<span
|
||||
className="label-container"
|
||||
>
|
||||
0.525
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
className="c5"
|
||||
className="c11"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
className="c6"
|
||||
className="c12"
|
||||
onClick={[Function]}
|
||||
selected={false}
|
||||
>
|
||||
Compute Optimized
|
||||
</button>
|
||||
<button
|
||||
className="c6"
|
||||
className="c12"
|
||||
onClick={[Function]}
|
||||
selected={false}
|
||||
>
|
||||
General Purpose
|
||||
</button>
|
||||
<button
|
||||
className="c6"
|
||||
className="c12"
|
||||
onClick={[Function]}
|
||||
selected={false}
|
||||
>
|
||||
Memory Optimized
|
||||
</button>
|
||||
<button
|
||||
className="c6"
|
||||
className="c12"
|
||||
onClick={[Function]}
|
||||
selected={false}
|
||||
>
|
||||
@ -827,7 +730,7 @@ exports[`renders <Filters /> without throwing 1`] = `
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
className="c7"
|
||||
className="c13"
|
||||
disabled={false}
|
||||
onClick={undefined}
|
||||
>
|
||||
|
@ -1,9 +1,21 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Row } from 'react-styled-flexboxgrid';
|
||||
import styled from 'styled-components';
|
||||
import { SectionNav } from '@components/navigation';
|
||||
import { Filters } from '@components/filters';
|
||||
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 {
|
||||
constructor(props) {
|
||||
@ -38,10 +50,7 @@ class Home extends Component {
|
||||
|
||||
onFilterChange({
|
||||
...filters,
|
||||
groups: [
|
||||
...otherGroups,
|
||||
{ name: group.name, selected: !group.selected }
|
||||
]
|
||||
groups: [...otherGroups, { name: group.name, selected: !group.selected }]
|
||||
});
|
||||
}
|
||||
|
||||
@ -60,7 +69,7 @@ class Home extends Component {
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<main>
|
||||
<Main>
|
||||
<SectionNav />
|
||||
<Breadcrumb>
|
||||
<BreadcrumbItem>Instances</BreadcrumbItem>
|
||||
@ -81,7 +90,11 @@ class Home extends Component {
|
||||
<Row>
|
||||
<PackagesHOC />
|
||||
</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
|
||||
href="/"
|
||||
name="Go to home"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<img
|
||||
alt="Triton Logo"
|
||||
className="c3"
|
||||
src="test-file-mock"
|
||||
/>
|
||||
|
@ -14,8 +14,8 @@ const StyledLogo = Img.extend`
|
||||
const NavHeader = () => (
|
||||
<Header>
|
||||
<HeaderBrand>
|
||||
<Link to="/">
|
||||
<StyledLogo src={Logo} />
|
||||
<Link to="/" name="Go to home">
|
||||
<StyledLogo src={Logo} alt="Triton Logo"/>
|
||||
</Link>
|
||||
</HeaderBrand>
|
||||
</Header>
|
||||
|
@ -253,7 +253,7 @@ exports[`renders <Packages /> without throwing 1`] = `
|
||||
}
|
||||
}
|
||||
|
||||
<ul
|
||||
<section
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
@ -760,5 +760,5 @@ exports[`renders <Packages /> without throwing 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</section>
|
||||
`;
|
||||
|
@ -5,7 +5,7 @@ import { Col } from 'react-styled-flexboxgrid';
|
||||
|
||||
import Package from '@components/package';
|
||||
|
||||
const ListStyled = styled.ul`
|
||||
const ListStyled = styled.section`
|
||||
display: flex;
|
||||
min-width: 100%;
|
||||
list-style: none;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -68,9 +68,11 @@ exports[`renders <Header /> without throwing 1`] = `
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
name="Go to home"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<img
|
||||
alt="Triton Logo"
|
||||
className="c3"
|
||||
src="test-file-mock"
|
||||
/>
|
||||
|
@ -253,7 +253,7 @@ exports[`renders <PackagesHOC /> without throwing 1`] = `
|
||||
}
|
||||
}
|
||||
|
||||
<ul
|
||||
<section
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
@ -1768,5 +1768,5 @@ exports[`renders <PackagesHOC /> without throwing 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</section>
|
||||
`;
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"presets": "joyent-portal",
|
||||
"presets": ["joyent-portal"],
|
||||
"plugins": [
|
||||
"styled-components",
|
||||
["inline-react-svg", {
|
||||
|
@ -10,22 +10,16 @@
|
||||
"lint:css": "echo 0",
|
||||
"lint-ci:css": "echo 0",
|
||||
"lint:js": "eslint . --fix",
|
||||
"lint-ci:js":
|
||||
"eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/ui-toolkit.xml",
|
||||
"lint-ci:js": "eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/ui-toolkit.xml",
|
||||
"lint": "redrun -s lint:*",
|
||||
"lint-ci": "redrun -s lint-ci:*",
|
||||
"test": "echo 0",
|
||||
"test-ci": "echo 0",
|
||||
"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",
|
||||
"compile-watch:es":
|
||||
"NODE_ENV=development babel src --out-dir dist/es --source-maps inline --watch",
|
||||
"compile:es":
|
||||
"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",
|
||||
"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",
|
||||
"compile-watch:es": "NODE_ENV=development babel src --out-dir dist/es --source-maps inline --watch",
|
||||
"compile:es": "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:*",
|
||||
"watch": "redrun copy-fonts && redrun -p compile-watch:*",
|
||||
"styleguide:build": "cross-env NODE_ENV=production styleguidist build",
|
||||
@ -64,6 +58,7 @@
|
||||
"unitcalc": "^1.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"csso": "^3.1.1",
|
||||
"eslint": "^4.5.0",
|
||||
"eslint-config-joyent-portal": "2.0.0",
|
||||
@ -88,8 +83,7 @@
|
||||
"stylelint": "^8.0.0",
|
||||
"stylelint-config-primer": "^2.0.1",
|
||||
"stylelint-config-standard": "^17.0.0",
|
||||
"stylelint-processor-styled-components":
|
||||
"styled-components/stylelint-processor-styled-components#2a33b5f",
|
||||
"stylelint-processor-styled-components": "styled-components/stylelint-processor-styled-components#2a33b5f",
|
||||
"svgo": "^0.7.2",
|
||||
"tinycolor2": "^1.4.1",
|
||||
"title-case": "^2.1.1",
|
||||
|
@ -10,16 +10,3 @@
|
||||
onChange={value => console.log(value)}
|
||||
>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 PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import InputRange from 'react-input-range';
|
||||
import InputRange from './react-input-range';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import theme from '../theme';
|
||||
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)`
|
||||
margin-bottom: ${remcalc(10)};
|
||||
@ -79,7 +32,7 @@ class Slider extends Component {
|
||||
const { minValue, maxValue, value } = this.state;
|
||||
const { children, ...rest } = this.props;
|
||||
return (
|
||||
<SliderStyled>
|
||||
<div>
|
||||
<Label>{children}</Label>
|
||||
<InputRange
|
||||
{...rest}
|
||||
@ -88,7 +41,7 @@ class Slider extends Component {
|
||||
value={value}
|
||||
onChange={value => this.changeValue(value)}
|
||||
/>
|
||||
</SliderStyled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -103,18 +56,6 @@ Slider.propTypes = {
|
||||
formatLabel: PropTypes.func,
|
||||
ariaLabelledby: 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,
|
||||
draggableTrack: PropTypes.bool,
|
||||
onChangeStart: PropTypes.func,
|
||||
@ -129,19 +70,7 @@ Slider.defaultProps = {
|
||||
? Math.round(value).toFixed(3)
|
||||
: value,
|
||||
onChangeStart: () => {},
|
||||
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'
|
||||
}
|
||||
step: 1
|
||||
};
|
||||
|
||||
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