aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/components
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2018-05-14 17:22:53 +0200
committerSonarTech <sonartech@sonarsource.com>2018-05-14 20:20:49 +0200
commit2c91ba5af11b8e5955b65d4f0f76ea0e8917afbd (patch)
tree2bd822b92f062b3117df2f54339a47469517c23b /server/sonar-web/src/main/js/components
parent7fb43549fb85a0f79e61106ab770338d868b033d (diff)
downloadsonarqube-2c91ba5af11b8e5955b65d4f0f76ea0e8917afbd.tar.gz
sonarqube-2c91ba5af11b8e5955b65d4f0f76ea0e8917afbd.zip
replace native buttons with Button component (#235)
Diffstat (limited to 'server/sonar-web/src/main/js/components')
-rw-r--r--server/sonar-web/src/main/js/components/controls/GlobalMessages.js8
-rw-r--r--server/sonar-web/src/main/js/components/controls/Toggle.js13
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.js4
-rw-r--r--server/sonar-web/src/main/js/components/controls/styles.css14
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueMessage.js8
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.js.snap2
-rw-r--r--server/sonar-web/src/main/js/components/ui/buttons.css220
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 */