mirror of https://github.com/apache/superset.git
Better looking checkboxes (#3345)
Also showing icon only on hover on control headers
This commit is contained in:
parent
e79adbbc5f
commit
254645773c
|
@ -9,15 +9,19 @@ const propTypes = {
|
|||
icon: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
placement: PropTypes.string,
|
||||
};
|
||||
const defaultProps = {
|
||||
icon: 'question-circle-o',
|
||||
icon: 'info-circle',
|
||||
className: 'text-muted',
|
||||
placement: 'right',
|
||||
};
|
||||
|
||||
export default function InfoTooltipWithTrigger({ label, tooltip, icon, className, onClick }) {
|
||||
export default function InfoTooltipWithTrigger({
|
||||
label, tooltip, icon, className, onClick, placement }) {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
placement={placement}
|
||||
overlay={<Tooltip id={`${slugify(label)}-tooltip`}>{tooltip}</Tooltip>}
|
||||
>
|
||||
<i
|
||||
|
|
|
@ -56,6 +56,7 @@ const defaultProps = {
|
|||
export default class Control extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { hovered: false };
|
||||
this.validate = this.validate.bind(this);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
|
@ -65,6 +66,9 @@ export default class Control extends React.PureComponent {
|
|||
onChange(value, errors) {
|
||||
this.validateAndSetValue(value, errors);
|
||||
}
|
||||
setHover(hovered) {
|
||||
this.setState({ hovered });
|
||||
}
|
||||
validateAndSetValue(value, errors) {
|
||||
let validationErrors = this.props.validationErrors;
|
||||
let currentErrors = this.validate(value);
|
||||
|
@ -96,9 +100,14 @@ export default class Control extends React.PureComponent {
|
|||
const ControlType = controlMap[this.props.type];
|
||||
const divStyle = this.props.hidden ? { display: 'none' } : null;
|
||||
return (
|
||||
<div style={divStyle}>
|
||||
<div
|
||||
style={divStyle}
|
||||
onMouseEnter={this.setHover.bind(this, true)}
|
||||
onMouseLeave={this.setHover.bind(this, false)}
|
||||
>
|
||||
<ControlType
|
||||
onChange={this.onChange}
|
||||
hovered={this.state.hovered}
|
||||
{...this.props}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -10,32 +10,72 @@ const propTypes = {
|
|||
renderTrigger: PropTypes.bool,
|
||||
rightNode: PropTypes.node,
|
||||
leftNode: PropTypes.node,
|
||||
onClick: PropTypes.func,
|
||||
hovered: PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
validationErrors: [],
|
||||
renderTrigger: false,
|
||||
hovered: false,
|
||||
};
|
||||
|
||||
export default function ControlHeader({
|
||||
label, description, validationErrors, renderTrigger, leftNode, rightNode }) {
|
||||
const hasError = (validationErrors.length > 0);
|
||||
export default class ControlHeader extends React.Component {
|
||||
renderOptionalIcons() {
|
||||
if (this.props.hovered) {
|
||||
return (
|
||||
<div>
|
||||
<span>
|
||||
{this.props.description &&
|
||||
<span>
|
||||
<InfoTooltipWithTrigger
|
||||
label="descr"
|
||||
tooltip={this.props.description}
|
||||
placement="top"
|
||||
/>
|
||||
{' '}
|
||||
</span>
|
||||
}
|
||||
{this.props.renderTrigger &&
|
||||
<span>
|
||||
<InfoTooltipWithTrigger
|
||||
label="bolt"
|
||||
tooltip={this.props.description}
|
||||
placement="top"
|
||||
icon="bolt"
|
||||
/>
|
||||
{' '}
|
||||
</span>
|
||||
}
|
||||
</span>);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
render() {
|
||||
const labelClass = (this.props.validationErrors.length > 0) ? 'text-danger' : '';
|
||||
return (
|
||||
<div
|
||||
className="ControlHeader"
|
||||
>
|
||||
<div className="pull-left">
|
||||
<ControlLabel>
|
||||
{hasError ?
|
||||
<strong className="text-danger">{label}</strong> :
|
||||
<span>{label}</span>
|
||||
{this.props.leftNode &&
|
||||
<span>{this.props.leftNode}</span>
|
||||
}
|
||||
<span
|
||||
onClick={this.props.onClick}
|
||||
className={labelClass}
|
||||
style={{ cursor: this.props.onClick ? 'pointer' : '' }}
|
||||
>
|
||||
{this.props.label}
|
||||
</span>
|
||||
{' '}
|
||||
{(validationErrors.length > 0) &&
|
||||
{(this.props.validationErrors.length > 0) &&
|
||||
<span>
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
placement="top"
|
||||
overlay={
|
||||
<Tooltip id={'error-tooltip'}>
|
||||
{validationErrors.join(' ')}
|
||||
{this.props.validationErrors.join(' ')}
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
|
@ -44,41 +84,19 @@ export default function ControlHeader({
|
|||
{' '}
|
||||
</span>
|
||||
}
|
||||
{description &&
|
||||
<span>
|
||||
<InfoTooltipWithTrigger label={label} tooltip={description} />
|
||||
{' '}
|
||||
</span>
|
||||
}
|
||||
{renderTrigger &&
|
||||
<span>
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
overlay={
|
||||
<Tooltip id={'rendertrigger-tooltip'}>
|
||||
Takes effect on chart immediatly
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<i className="fa fa-bolt text-muted" />
|
||||
</OverlayTrigger>
|
||||
{' '}
|
||||
</span>
|
||||
}
|
||||
{leftNode &&
|
||||
<span>{leftNode}</span>
|
||||
}
|
||||
{this.renderOptionalIcons()}
|
||||
</ControlLabel>
|
||||
</div>
|
||||
{rightNode &&
|
||||
{this.props.rightNode &&
|
||||
<div className="pull-right">
|
||||
{rightNode}
|
||||
{this.props.rightNode}
|
||||
</div>
|
||||
}
|
||||
<div className="clearfix" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ControlHeader.propTypes = propTypes;
|
||||
ControlHeader.defaultProps = defaultProps;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Checkbox } from 'react-bootstrap';
|
||||
import ControlHeader from '../ControlHeader';
|
||||
|
||||
const propTypes = {
|
||||
|
@ -24,11 +23,16 @@ export default class CheckboxControl extends React.Component {
|
|||
return (
|
||||
<ControlHeader
|
||||
{...this.props}
|
||||
onClick={this.onToggle.bind(this)}
|
||||
leftNode={
|
||||
<Checkbox
|
||||
checked={this.props.value}
|
||||
onChange={this.onToggle.bind(this)}
|
||||
<span>
|
||||
<i
|
||||
className={`fa fa-check ${this.props.value ? 'text-primary' : 'text-transparent'}`}
|
||||
onClick={this.onToggle.bind(this)}
|
||||
style={{ border: '1px solid #aaa', borderRadius: '2px', cursor: 'pointer' }}
|
||||
/>
|
||||
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
"react-addons-css-transition-group": "^15.6.0",
|
||||
"react-addons-shallow-compare": "^15.4.2",
|
||||
"react-alert": "^1.0.14",
|
||||
"react-bootstrap": "^0.31.0",
|
||||
"react-bootstrap": "^0.31.2",
|
||||
"react-bootstrap-table": "^3.1.7",
|
||||
"react-dom": "^15.5.1",
|
||||
"react-gravatar": "^2.6.1",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable no-unused-expressions */
|
||||
import React from 'react';
|
||||
import { Checkbox } from 'react-bootstrap';
|
||||
import sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { describe, it, beforeEach } from 'mocha';
|
||||
|
@ -28,6 +27,6 @@ describe('CheckboxControl', () => {
|
|||
expect(controlHeader).to.have.lengthOf(1);
|
||||
|
||||
const headerWrapper = controlHeader.shallow();
|
||||
expect(headerWrapper.find(Checkbox)).to.have.length(1);
|
||||
expect(headerWrapper.find('i.fa-check')).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -329,3 +329,6 @@ iframe {
|
|||
border: none;
|
||||
width: 100%;
|
||||
}
|
||||
.text-transparent {
|
||||
color: transparent;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue