Skip to content

Commit b4a6542

Browse files
committed
first commit
1 parent 39953d0 commit b4a6542

File tree

5 files changed

+244
-18
lines changed

5 files changed

+244
-18
lines changed

package-lock.json

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
"@testing-library/jest-dom": "^5.17.0",
77
"@testing-library/react": "^13.4.0",
88
"@testing-library/user-event": "^13.5.0",
9+
"prop-types": "^15.8.1",
910
"react": "^18.3.1",
1011
"react-dom": "^18.3.1",
1112
"react-scripts": "5.0.1",
13+
"sass": "^1.77.8",
1214
"web-vitals": "^2.1.4"
1315
},
1416
"scripts": {

src/App.js

+17-18
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
1-
import logo from './logo.svg';
2-
import './App.css';
1+
import React, { useState } from "react";
2+
import ToggleSwitch from "./ToggleSwitch/ToggleSwitch";
33

44
function App() {
5+
let [newsletter, setNewsletter] = useState(false);
6+
7+
const onNewsletterChange = (checked) => {
8+
setNewsletter(checked);
9+
};
10+
511
return (
6-
<div className="App">
7-
<header className="App-header">
8-
<img src={logo} className="App-logo" alt="logo" />
9-
<p>
10-
Edit <code>src/App.js</code> and save to reload.
11-
</p>
12-
<a
13-
className="App-link"
14-
href="https://reactjs.org"
15-
target="_blank"
16-
rel="noopener noreferrer"
17-
>
18-
Learn React
19-
</a>
20-
</header>
21-
</div>
12+
<>
13+
<ToggleSwitch
14+
id="newsletter"
15+
checked={newsletter}
16+
onChange={onNewsletterChange}
17+
/>
18+
<label htmlFor="newsletter">Subscribe to our Newsletter</label>
19+
</>
2220
);
2321
}
2422

23+
2524
export default App;

src/ToggleSwitch/ToggleSwitch.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import './ToggleSwitch.scss';
4+
5+
/*
6+
Toggle Switch Component
7+
Note: id, checked and onChange are required for ToggleSwitch component to function.
8+
The props name, small, disabled and optionLabels are optional.
9+
Usage: <ToggleSwitch id={id} checked={value} onChange={checked => setValue(checked)}} />
10+
*/
11+
12+
const ToggleSwitch = ({ id, name, checked, onChange, optionLabels, small, disabled }) => {
13+
function handleKeyPress(e){
14+
if (e.keyCode !== 32) return;
15+
16+
e.preventDefault();
17+
onChange(!checked)
18+
}
19+
20+
return (
21+
<div className={"toggle-switch" + (small ? " small-switch" : "")}>
22+
<input
23+
type="checkbox"
24+
name={name}
25+
className="toggle-switch-checkbox"
26+
id={id}
27+
checked={checked}
28+
onChange={e => onChange(e.target.checked)}
29+
disabled={disabled}
30+
/>
31+
{id ? (
32+
<label className="toggle-switch-label"
33+
htmlFor={id}
34+
tabIndex={ disabled ? -1 : 1 }
35+
onKeyDown={ (e) => { handleKeyPress(e) }}>
36+
<span
37+
className={
38+
disabled
39+
? "toggle-switch-inner toggle-switch-disabled"
40+
: "toggle-switch-inner"
41+
}
42+
data-yes={optionLabels[0]}
43+
data-no={optionLabels[1]}
44+
tabIndex={-1}
45+
/>
46+
<span
47+
className={
48+
disabled
49+
? "toggle-switch-switch toggle-switch-disabled"
50+
: "toggle-switch-switch"
51+
}
52+
tabIndex={-1}
53+
/>
54+
</label>
55+
) : null}
56+
</div>
57+
);
58+
}
59+
60+
// Set optionLabels for rendering.
61+
ToggleSwitch.defaultProps = {
62+
optionLabels: ["Yes", "No"],
63+
};
64+
65+
ToggleSwitch.propTypes = {
66+
id: PropTypes.string.isRequired,
67+
checked: PropTypes.bool.isRequired,
68+
onChange: PropTypes.func.isRequired,
69+
name: PropTypes.string,
70+
optionLabels: PropTypes.array,
71+
small: PropTypes.bool,
72+
disabled: PropTypes.bool
73+
};
74+
75+
export default ToggleSwitch;

src/ToggleSwitch/ToggleSwitch.scss

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Colors
2+
$label-colour: #bbb;
3+
$disabled-colour: #ddd;
4+
$toggle-colour: #2F855A;
5+
$white: #fff;
6+
$focus-color: #ff0;
7+
8+
.toggle-switch {
9+
position: relative;
10+
margin-right: 10px;
11+
width: 75px;
12+
display: inline-block;
13+
vertical-align: middle;
14+
-webkit-user-select: none;
15+
-moz-user-select: none;
16+
-ms-user-select: none;
17+
text-align: left;
18+
&-checkbox {
19+
display: none;
20+
}
21+
&-label {
22+
display: block;
23+
overflow: hidden;
24+
cursor: pointer;
25+
border: 0 solid $label-colour;
26+
border-radius: 20px;
27+
margin: 0;
28+
&:focus {
29+
outline: none;
30+
> span {
31+
box-shadow: 0 0 2px 5px $focus-color;
32+
}
33+
}
34+
> span:focus {
35+
outline: none;
36+
}
37+
}
38+
&-inner {
39+
display: block;
40+
width: 200%;
41+
margin-left: -100%;
42+
transition: margin 0.3s ease-in 0s;
43+
&:before,
44+
&:after {
45+
display: block;
46+
float: left;
47+
width: 50%;
48+
height: 34px;
49+
padding: 0;
50+
line-height: 34px;
51+
font-size: 14px;
52+
color: white;
53+
font-weight: bold;
54+
box-sizing: border-box;
55+
}
56+
&:before {
57+
content: attr(data-yes);
58+
text-transform: uppercase;
59+
padding-left: 10px;
60+
background-color: $toggle-colour;
61+
color: $white;
62+
}
63+
}
64+
&-disabled {
65+
background-color: $disabled-colour;
66+
cursor: not-allowed;
67+
&:before {
68+
background-color: $disabled-colour;
69+
cursor: not-allowed;
70+
}
71+
}
72+
&-inner:after {
73+
content: attr(data-no);
74+
text-transform: uppercase;
75+
padding-right: 10px;
76+
background-color: $label-colour;
77+
color: $white;
78+
text-align: right;
79+
}
80+
&-switch {
81+
display: block;
82+
width: 24px;
83+
margin: 5px;
84+
background: $white;
85+
position: absolute;
86+
top: 0;
87+
bottom: 0;
88+
right: 40px;
89+
border: 0 solid $label-colour;
90+
border-radius: 20px;
91+
transition: all 0.3s ease-in 0s;
92+
}
93+
&-checkbox:checked + &-label {
94+
.toggle-switch-inner {
95+
margin-left: 0;
96+
}
97+
.toggle-switch-switch {
98+
right: 0px;
99+
}
100+
}
101+
&.small-switch {
102+
width: 40px;
103+
.toggle-switch-inner {
104+
&:after,
105+
&:before {
106+
content: "";
107+
height: 20px;
108+
line-height: 20px;
109+
}
110+
}
111+
.toggle-switch-switch {
112+
width: 16px;
113+
right: 20px;
114+
margin: 2px;
115+
}
116+
}
117+
@media screen and (max-width: 991px) {
118+
119+
transform: scale(0.9);
120+
}
121+
@media screen and (max-width: 767px) {
122+
transform: scale(0.825);
123+
}
124+
@media screen and (max-width: 575px) {
125+
transform: scale(0.75);
126+
}
127+
}

0 commit comments

Comments
 (0)