-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
10267 add cornerstone toggle to sidebar #668
Changes from all commits
cbe54a0
21dcb54
5b583cf
574b38b
bec7af7
8a15cf0
3e2531a
46bf775
a332e47
2500e78
2c231d6
b0eadd2
5174081
442ff3b
42110ff
f243ce6
5dc58b2
dbfce44
bb476f8
50bd497
a546717
43a0d17
151386e
7a43c0e
d626b5a
e53ea6a
a17346c
224c201
8b863c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React from "react"; | ||
import PropTypes from "prop-types"; | ||
import styled from "styled-components"; | ||
import Toggle from "../../Shared/components/Toggle"; | ||
import { __ } from "@wordpress/i18n"; | ||
|
||
const Cornerstone = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
margin-top: 5px; | ||
|
||
label { | ||
margin-right: 10px; | ||
flex-shrink: 0; | ||
max-width: 75%; | ||
} | ||
`; | ||
|
||
class CornerstoneToggle extends React.Component { | ||
/** | ||
* Renders the CornerstoneToggle component. | ||
* | ||
* @returns {ReactElement} the CornerstoneToggle component. | ||
*/ | ||
render() { | ||
return ( | ||
<Cornerstone> | ||
<Toggle | ||
id="cornerstone_toggle" | ||
ariaLabel={ __( "Mark this post as cornerstone content", "yoast-components" ) } | ||
labelText={ __( "Mark this as cornerstone content.", "yoast-components" ) } | ||
isEnabled={ this.props.isEnabled } | ||
onSetToggleState={ this.props.onToggle } | ||
onToggleDisabled={ this.props.onToggleDisabled } | ||
/> | ||
</Cornerstone> | ||
); | ||
} | ||
} | ||
|
||
CornerstoneToggle.propTypes = { | ||
isEnabled: PropTypes.bool, | ||
onSetToggleState: PropTypes.func, | ||
onToggle: PropTypes.func, | ||
disable: PropTypes.bool, | ||
onToggleDisabled: PropTypes.func, | ||
}; | ||
|
||
export default CornerstoneToggle; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React from "react"; | ||
import renderer from "react-test-renderer"; | ||
import CornerstoneToggle from "../components/CornerstoneToggle"; | ||
|
||
test( "The CornerstoneToggle matches the snapshot", () => { | ||
const component = renderer.create( | ||
<CornerstoneToggle onChange={ () => {} } checked={ true } /> | ||
); | ||
|
||
let tree = component.toJSON(); | ||
expect( tree ).toMatchSnapshot(); | ||
} ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`The CornerstoneToggle matches the snapshot 1`] = ` | ||
.c2 { | ||
background-color: #ccc; | ||
border-radius: 7px; | ||
height: 14px; | ||
width: 30px; | ||
cursor: pointer; | ||
margin: 0; | ||
outline: 0; | ||
} | ||
|
||
.c2:focus > span { | ||
box-shadow: inset 0 0 0 1px #fff,0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8); | ||
} | ||
|
||
.c3 { | ||
background-color: #888; | ||
margin-left: -2px; | ||
box-shadow: 0 2px 2px 2px rgba(0,0,0,0.1); | ||
border-radius: 100%; | ||
height: 20px; | ||
width: 20px; | ||
position: absolute; | ||
margin-top: -3px; | ||
} | ||
|
||
.c4 { | ||
font-size: 14px; | ||
line-height: 20px; | ||
width: 30px; | ||
text-align: center; | ||
display: inline-block; | ||
margin: 0; | ||
font-style: italic; | ||
} | ||
|
||
.c1 { | ||
display: -webkit-box; | ||
display: -webkit-flex; | ||
display: -ms-flexbox; | ||
display: flex; | ||
-webkit-box-pack: justify; | ||
-webkit-justify-content: space-between; | ||
-ms-flex-pack: justify; | ||
justify-content: space-between; | ||
-webkit-align-items: center; | ||
-webkit-box-align: center; | ||
-ms-flex-align: center; | ||
align-items: center; | ||
} | ||
|
||
.c0 { | ||
display: -webkit-box; | ||
display: -webkit-flex; | ||
display: -ms-flexbox; | ||
display: flex; | ||
-webkit-box-pack: justify; | ||
-webkit-justify-content: space-between; | ||
-ms-flex-pack: justify; | ||
justify-content: space-between; | ||
-webkit-align-items: center; | ||
-webkit-box-align: center; | ||
-ms-flex-align: center; | ||
align-items: center; | ||
margin-top: 5px; | ||
} | ||
|
||
.c0 label { | ||
margin-right: 10px; | ||
-webkit-flex-shrink: 0; | ||
-ms-flex-negative: 0; | ||
flex-shrink: 0; | ||
max-width: 75%; | ||
} | ||
|
||
<div | ||
className="c0" | ||
> | ||
<div | ||
className="c1" | ||
> | ||
<label | ||
htmlFor="cornerstone_toggle" | ||
onClick={[Function]} | ||
> | ||
Mark this as cornerstone content. | ||
</label> | ||
<div | ||
aria-checked={false} | ||
aria-label="Mark this post as cornerstone content" | ||
className="c2" | ||
id="cornerstone_toggle" | ||
onClick={[Function]} | ||
onKeyDown={[Function]} | ||
role="checkbox" | ||
tabIndex="0" | ||
> | ||
<span | ||
className="c3" | ||
/> | ||
</div> | ||
<span | ||
aria-hidden="true" | ||
className="c4" | ||
> | ||
Off | ||
</span> | ||
</div> | ||
</div> | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import PropTypes from "prop-types"; | ||
import React from "react"; | ||
import styled from "styled-components"; | ||
import colors from "../../../../style-guide/colors.json"; | ||
import { __ } from "@wordpress/i18n"; | ||
|
||
const ToggleBar = styled.div` | ||
background-color: ${ props => props.isEnabled ? "#a5d6a7" : colors.$color_button_border }; | ||
border-radius: 7px; | ||
height: 14px; | ||
width: 30px; | ||
cursor: pointer; | ||
margin: 0; | ||
outline: 0; | ||
&:focus > span { | ||
box-shadow: inset 0 0 0 1px ${colors.$color_white}, 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure as to why the first color is variable, but the other two are not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This applies also to In a way, |
||
} | ||
`; | ||
|
||
const ToggleBullet = styled.span` | ||
background-color: ${ props => props.isEnabled ? colors.$color_green_medium_light : colors.$color_grey_medium_dark }; | ||
margin-left: ${ props => props.isEnabled ? "12px" : "-2px" }; | ||
box-shadow: 0 2px 2px 2px rgba(0, 0, 0, 0.1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here: this is a hardcoded color. We should use a color from the palette (not necessarily a rgba color) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi Andrea, you are right. But we'll skip this for now to finish the component. We'll pick this up again during the polishing process. |
||
border-radius: 100%; | ||
height: 20px; | ||
width: 20px; | ||
position: absolute; | ||
margin-top: -3px; | ||
`; | ||
|
||
const ToggleVisualLabel = styled.span` | ||
font-size: 14px; | ||
line-height: 20px; | ||
width: 30px; | ||
text-align: center; | ||
display: inline-block; | ||
margin: 0; | ||
font-style: italic; | ||
`; | ||
|
||
const ToggleDiv = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
`; | ||
|
||
class Toggle extends React.Component { | ||
/** | ||
* Sets the toggle object. | ||
* | ||
* @param {Object} props The props to use. | ||
* | ||
* @returns {void} | ||
*/ | ||
constructor( props ) { | ||
super( props ); | ||
|
||
this.onClick = this.props.onToggleDisabled; | ||
|
||
this.setToggleState = this.setToggleState.bind( this ); | ||
|
||
if ( props.disable !== true ) { | ||
this.onClick = this.setToggleState.bind( this ); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the rendered HTML. | ||
* | ||
* @returns {ReactElement} The rendered HTML. | ||
*/ | ||
render() { | ||
return( | ||
<ToggleDiv> | ||
{ /* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions */ } | ||
<label | ||
htmlFor={ this.props.id } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not important enough for now, and also more a preference than an instruction. but when props are used in multiple places, it's nice to extract props to local variables, this is done, for example, in SnippetEditorFields.js. |
||
onClick={ this.onClick } | ||
> | ||
{ this.props.labelText } | ||
</label> | ||
<ToggleBar | ||
isEnabled={ this.props.isEnabled } | ||
onClick={ this.onClick } | ||
onKeyDown={ this.setToggleState } | ||
tabIndex="0" | ||
role="checkbox" | ||
aria-label={ this.props.ariaLabel } | ||
aria-checked={ this.props.isEnabled } | ||
id={ this.props.id } | ||
> | ||
<ToggleBullet isEnabled={ this.props.isEnabled } /> | ||
</ToggleBar> | ||
<ToggleVisualLabel aria-hidden="true"> | ||
{ this.props.isEnabled ? __( "On", "yoast-components" ) : __( "Off", "yoast-components" ) } | ||
</ToggleVisualLabel> | ||
</ToggleDiv> | ||
); | ||
} | ||
|
||
/** | ||
* Sets the state to the opposite of the current state. | ||
* | ||
* @param {Object} event React SyntheticEvent. | ||
* | ||
* @returns {void} | ||
*/ | ||
setToggleState( event ) { | ||
// Makes the toggle actionable with the Space bar key. | ||
if ( event.type === "keydown" && event.keyCode !== 32 ) { | ||
return; | ||
} | ||
|
||
this.props.onSetToggleState( ! this.props.isEnabled ); | ||
} | ||
} | ||
|
||
Toggle.propTypes = { | ||
isEnabled: PropTypes.bool, | ||
ariaLabel: PropTypes.string.isRequired, | ||
onSetToggleState: PropTypes.func, | ||
disable: PropTypes.bool, | ||
onToggleDisabled: PropTypes.func, | ||
id: PropTypes.string.isRequired, | ||
labelText: PropTypes.string, | ||
}; | ||
|
||
Toggle.defaultProps = { | ||
isEnabled: false, | ||
onSetToggleState: () => {}, | ||
disable: false, | ||
labelText: "", | ||
}; | ||
|
||
export default Toggle; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We usually set defaults for PropTypes that are not required.