diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-05-14 17:22:53 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-05-14 20:20:49 +0200 |
commit | 2c91ba5af11b8e5955b65d4f0f76ea0e8917afbd (patch) | |
tree | 2bd822b92f062b3117df2f54339a47469517c23b /server/sonar-web/src/main/js/components | |
parent | 7fb43549fb85a0f79e61106ab770338d868b033d (diff) | |
download | sonarqube-2c91ba5af11b8e5955b65d4f0f76ea0e8917afbd.tar.gz sonarqube-2c91ba5af11b8e5955b65d4f0f76ea0e8917afbd.zip |
replace native buttons with Button component (#235)
Diffstat (limited to 'server/sonar-web/src/main/js/components')
7 files changed, 234 insertions, 35 deletions
diff --git a/server/sonar-web/src/main/js/components/controls/GlobalMessages.js b/server/sonar-web/src/main/js/components/controls/GlobalMessages.js index 6e5df20efcb..0d0782009b7 100644 --- a/server/sonar-web/src/main/js/components/controls/GlobalMessages.js +++ b/server/sonar-web/src/main/js/components/controls/GlobalMessages.js @@ -21,6 +21,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { ERROR, SUCCESS } from '../../store/globalMessages/duck'; +import { Button } from '../ui/buttons'; export default class GlobalMessages extends React.PureComponent { static propTypes = { @@ -40,14 +41,13 @@ export default class GlobalMessages extends React.PureComponent { 'process-spinner-success': message.level === SUCCESS }); return ( - <div key={message.id} className={className}> + <div className={className} key={message.id}> {message.message} - <button + <Button className="process-spinner-close" - type="button" onClick={() => this.props.closeGlobalMessage(message.id)}> <i className="icon-close" /> - </button> + </Button> </div> ); }; diff --git a/server/sonar-web/src/main/js/components/controls/Toggle.js b/server/sonar-web/src/main/js/components/controls/Toggle.js index b1b18b3a78b..4cbabfece09 100644 --- a/server/sonar-web/src/main/js/components/controls/Toggle.js +++ b/server/sonar-web/src/main/js/components/controls/Toggle.js @@ -20,6 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import { Button } from '../ui/buttons'; import './styles.css'; export default class Toggle extends React.PureComponent { @@ -29,13 +30,11 @@ export default class Toggle extends React.PureComponent { onChange: PropTypes.func }; - handleClick(e, value) { - e.preventDefault(); - e.currentTarget.blur(); + handleClick = value => { if (this.props.onChange) { this.props.onChange(!value); } - } + }; render() { const { value } = this.props; @@ -44,12 +43,12 @@ export default class Toggle extends React.PureComponent { const className = classNames('boolean-toggle', { 'boolean-toggle-on': booleanValue }); return ( - <button + <Button className={className} name={this.props.name} - onClick={e => this.handleClick(e, booleanValue)}> + onClick={() => this.handleClick(booleanValue)}> <div className="boolean-toggle-handle" /> - </button> + </Button> ); } } diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js b/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js index c371c10e730..3245074388a 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js +++ b/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js @@ -23,12 +23,12 @@ import Toggle from '../Toggle'; import { click } from '../../../helpers/testUtils'; function getSample(props) { - return <Toggle value={true} onChange={() => true} {...props} />; + return <Toggle onChange={() => true} value={true} {...props} />; } it('should render', () => { const Toggle = shallow(getSample()); - expect(Toggle.is('button')).toBe(true); + expect(Toggle.is('Button')).toBe(true); }); it('should call onChange', () => { diff --git a/server/sonar-web/src/main/js/components/controls/styles.css b/server/sonar-web/src/main/js/components/controls/styles.css index a68db8e3879..32fb0c19f36 100644 --- a/server/sonar-web/src/main/js/components/controls/styles.css +++ b/server/sonar-web/src/main/js/components/controls/styles.css @@ -81,7 +81,7 @@ width: 70px; } -.boolean-toggle { +.button.boolean-toggle { display: inline-block; vertical-align: middle; width: 48px; @@ -95,11 +95,11 @@ transition: all 0.3s ease; } -.boolean-toggle:hover { +.button.boolean-toggle:hover { background-color: #fff; } -.boolean-toggle:focus { +.button.boolean-toggle:focus { border-color: var(--blue); background-color: #f6f6f6; } @@ -114,20 +114,20 @@ transition: transform 0.3s cubic-bezier(0.87, -0.41, 0.19, 1.44), border 0.3s ease; } -.boolean-toggle-on { +.button.boolean-toggle-on { border-color: var(--darkBlue); background-color: var(--darkBlue); } -.boolean-toggle-on:hover { +.button.boolean-toggle-on:hover { background-color: var(--darkBlue); } -.boolean-toggle-on:focus { +.button.boolean-toggle-on:focus { background-color: var(--darkBlue); } -.boolean-toggle-on .boolean-toggle-handle { +.button.boolean-toggle-on .boolean-toggle-handle { border-color: #f6f6f6; transform: translateX(var(--controlHeight)); } diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueMessage.js b/server/sonar-web/src/main/js/components/issue/components/IssueMessage.js index 1f8a9cb2ae5..74bf39609ab 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueMessage.js +++ b/server/sonar-web/src/main/js/components/issue/components/IssueMessage.js @@ -22,6 +22,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import Tooltip from '../../controls/Tooltip'; import { translate, translateWithParameters } from '../../../helpers/l10n'; +import { Button } from '../../ui/buttons'; export default class IssueMessage extends React.PureComponent { /*:: props: { @@ -36,8 +37,7 @@ export default class IssueMessage extends React.PureComponent { workspace: PropTypes.object.isRequired }; - handleClick = (e /*: MouseEvent */) => { - e.preventDefault(); + handleClick = () => { this.context.workspace.openRule({ key: this.props.rule, organization: this.props.organization @@ -48,9 +48,9 @@ export default class IssueMessage extends React.PureComponent { return ( <div className="issue-message"> {this.props.message} - <button - className="button-link issue-rule icon-ellipsis-h little-spacer-left" + <Button aria-label={translate('issue.rule_details')} + className="button-link issue-rule icon-ellipsis-h little-spacer-left" onClick={this.handleClick} /> {this.props.engine && ( diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.js.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.js.snap index 9bf92a16d15..91587572e88 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.js.snap +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.js.snap @@ -5,7 +5,7 @@ exports[`should render with the message and a link to open the rule 1`] = ` className="issue-message" > Reduce the number of conditional operators (4) used in the expression - <button + <Button aria-label="issue.rule_details" className="button-link issue-rule icon-ellipsis-h little-spacer-left" onClick={[Function]} diff --git a/server/sonar-web/src/main/js/components/ui/buttons.css b/server/sonar-web/src/main/js/components/ui/buttons.css index 3df0420fc49..ea2ff4b6b13 100644 --- a/server/sonar-web/src/main/js/components/ui/buttons.css +++ b/server/sonar-web/src/main/js/components/ui/buttons.css @@ -17,10 +17,209 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +.button { + display: inline-block; + vertical-align: baseline; + height: var(--controlHeight); + line-height: calc(var(--controlHeight) - 2px); + padding: 0 12px; + border: 1px solid var(--darkBlue); + border-radius: 2px; + box-sizing: border-box; + background: transparent; + color: var(--darkBlue); + font-weight: 600; + font-size: var(--smallFontSize); + text-align: center; + text-decoration: none; + cursor: pointer; + outline: none; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.button:hover, +.button.button-active { + background: var(--darkBlue); + color: #fff; +} + +.button:active { + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.button:focus { + box-shadow: 0 0 0 3px rgba(35, 106, 151, 0.25); +} + +.button.disabled, +.button:disabled, +.button:disabled:hover, +.button:disabled:active, +.button:disabled:focus { + color: var(--disableGrayText) !important; + border-color: var(--disableGrayBorder) !important; + background: var(--disableGrayBg) !important; + cursor: not-allowed !important; + box-shadow: none !important; +} + +.button svg { + margin-top: calc((var(--controlHeight) - 16px - 2px) / 2); +} + +/* #region .button-red */ +.button-red { + border-color: var(--red); + color: var(--red); +} + +.button-red:hover, +.button-red.active { + background: var(--red); + color: #fff; +} -/* use double selector .button-icon.button-icon to increase the specificity */ +.button-red:focus { + box-shadow: 0 0 0 3px rgba(212, 51, 63, 0.25); +} +/* #endregion */ + +/* #region .button-success */ +.button-success { + border-color: var(--green); + color: var(--green); +} + +.button-success:hover, +.button-success.active { + background: var(--green); + color: #fff; +} + +.button-success:focus { + box-shadow: 0 0 0 3px rgba(0, 170, 0, 0.25); +} +/* #endregion */ + +/* #region .button-grey */ +.button-grey { + border-color: var(--gray71); + color: var(--secondFontColor); +} + +.button-grey:hover, +.button-grey.active { + background: var(--gray71); + color: #ffffff; +} + +.button-grey:focus { + box-shadow: 0 0 0 3px rgba(180, 180, 180, 0.25); +} +/* #endregion */ + +/* #region .button-link */ +.button-link { + display: inline; + height: auto; /* Keep this to not inherit the height from .button */ + margin: 0; + padding: 0; + border: none; + background: transparent; + color: var(--darkBlue); + font-weight: 400; + font-size: inherit; + line-height: inherit; + transition: all 0.2s ease; +} + +.button-link svg { + margin-top: 0; +} + +.button-link:hover { + background: transparent; + color: var(--blue); +} + +.button-link:active { + box-shadow: none; + outline: thin dotted #ccc; +} + +.button-link:disabled, +.button-link:disabled:hover, +.button-link:disabled:active, +.button-link:disabled:focus { + color: var(--secondFontColor); + background: transparent !important; + cursor: default; +} +/* #endregion */ + +.button-small { + height: var(--smallControlHeight); + line-height: 18px; + padding: 0 6px; + font-size: 11px; +} + +.button-small > svg { + margin-top: 2px; +} + +/* #region .button-group */ +.button-group { + display: inline-block; + vertical-align: middle; + font-size: 0; + white-space: nowrap; +} + +.button-group > button, +.button-group > .button { + position: relative; + z-index: var(--normalZIndex); + display: inline-block; + vertical-align: middle; + margin: 0; + cursor: pointer; +} + +.button-group > .button:hover:not(:disabled), +.button-group > .button:focus:not(:disabled), +.button-group > .button:active:not(:disabled), +.button-group > .button.active:not(:disabled) { + z-index: var(--aboveNormalZIndex); +} + +.button-group > .button:disabled { + z-index: var(--belowNormalZIndex); +} + +.button-group > .button:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.button-group > .button:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.button-group > .button + .button { + margin-left: -1px; +} + +.button-group > a:not(.button) { + vertical-align: middle; + margin: 0 8px; + font-size: var(--smallFontSize); +} +/* #endregion */ -.button-icon.button-icon { +/* #region .button-icon */ +.button-icon { display: inline-flex; justify-content: center; align-items: center; @@ -32,32 +231,33 @@ color: inherit; } -.button-icon.button-icon.button-small { +.button-icon.button-small { width: var(--smallControlHeight); height: var(--smallControlHeight); padding: 0; } -.button-icon.button-icon.button-small svg { +.button-icon.button-small svg { margin-top: 0; } -.button-icon.button-icon.button-tiny { +.button-icon.button-tiny { width: var(--tinyControlHeight); height: var(--tinyControlHeight); padding: 0; } -.button-icon.button-icon.button-tiny svg { +.button-icon.button-tiny svg { margin-top: 0; } -.button-icon.button-icon:hover, -.button-icon.button-icon:focus { +.button-icon:hover, +.button-icon:focus { background-color: currentColor; } -.button-icon.button-icon:hover svg, -.button-icon.button-icon:focus svg { +.button-icon:hover svg, +.button-icon:focus svg { color: #fff; } +/* #endregion */ |