Skip to content

Commit

Permalink
✨ [feature] 添加Switch组件.
Browse files Browse the repository at this point in the history
  • Loading branch information
lanjingling0510 committed Mar 31, 2017
1 parent 04e3a73 commit 33cd421
Show file tree
Hide file tree
Showing 12 changed files with 344 additions and 27 deletions.
1 change: 1 addition & 0 deletions components/identifiers.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ export const PAGINATION = 'CQPAGINATION';
export const TAG = 'CQTAG';
export const TABLE = 'CQTABLE';
export const LOADER = 'CQLOADER';
export const SWITCH = 'CQSWITCH';
83 changes: 83 additions & 0 deletions components/switch/Switch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';

const factory = (Thumb) => {
class Switch extends Component {
static propTypes = {
checked: PropTypes.bool,
className: PropTypes.string,
disabled: PropTypes.bool,
label: PropTypes.string,
name: PropTypes.string,
onBlur: PropTypes.func,
onChange: PropTypes.func,
onFocus: PropTypes.func,
ripple: PropTypes.bool,
theme: PropTypes.shape({
disabled: PropTypes.string,
field: PropTypes.string,
input: PropTypes.string,
off: PropTypes.string,
on: PropTypes.string,
ripple: PropTypes.string,
text: PropTypes.string,
thumb: PropTypes.string,
}),
};

static defaultProps = {
checked: false,
className: '',
disabled: false,
};

handleToggle = (event) => {
if (event.pageX !== 0 && event.pageY !== 0) this.blur();
if (!this.props.disabled && this.props.onChange) {
this.props.onChange(!this.props.checked, event);
}
};

blur() {
this.inputNode.blur();
}

focus() {
this.inputNode.focus();
}

render() {
const {
checked,
className,
disabled,
onChange, // eslint-disable-line no-unused-vars
ripple,
theme,
...others
} = this.props;
const _className = classnames(theme[disabled ? 'disabled' : 'field'], className);
return (
<label data-react-toolbox="switch" className={_className}>
<input
{...others}
checked={this.props.checked}
className={theme.input}
onClick={this.handleToggle}
readOnly
ref={(node) => { this.inputNode = node; }}
type="checkbox"
/>
<span className={theme[checked ? 'on' : 'off']}>
<Thumb disabled={this.props.disabled} theme={theme} ripple={ripple} />
</span>
{this.props.label ? <span className={theme.text}>{this.props.label}</span> : null}
</label>
);
}
}

return Switch;
};

export { factory as switchFactory };
20 changes: 20 additions & 0 deletions components/switch/Thumb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { PropTypes } from 'react';

const factory = (ripple) => {
const Thumb = ({theme, ...other }) => (
<span className={theme.thumb} {...other} />
);

Thumb.propTypes = {
children: PropTypes.node,
onMouseDown: PropTypes.func,
theme: PropTypes.shape({
ripple: PropTypes.string,
thumb: PropTypes.string,
}),
};

return ripple(Thumb);
};

export default factory;
24 changes: 24 additions & 0 deletions components/switch/config.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
:root {
--switch-color: var(--color-primary);
--switch-text-color: var(--color-text);
--switch-thumb-off-color: var(--palette-grey-50);
--switch-track-on-color: color(var(--color-primary) a(50%));
--switch-track-off-color: color(var(--color-black) a(26%));
--switch-off-ripple-color: color(var(--color-black) a(40%));
--switch-on-focus-color: color(var(--color-primary) a(26%));
--switch-off-focus-color: color(var(--color-black) a(10%));
--switch-disabled-thumb-color: var(--palette-grey-400);
--switch-disabled-track-color: color(var(--color-black) a(12%));
--switch-disabled-text-color: color(var(--color-black) a(26%));
--switch-total-height: calc(2.4 * var(--unit));
--switch-track-length: calc(3.6 * var(--unit));
--switch-track-height: calc(1.4 * var(--unit));
--switch-thumb-size: calc(2 * var(--unit));
--switch-thumb-on-color: var(--switch-color);
--switch-focus-init-size: calc(0.8 * var(--unit));
--switch-focus-size: calc(var(--switch-total-height) * 2);
--switch-focus-diff: calc((var(--switch-focus-size) - var(--switch-focus-init-size)) / 2);
--switch-ripple-duration: 650ms;
--switch-font-size: var(--font-size);
--switch-field-margin-bottom: calc(1.5 * var(--unit));
}
14 changes: 14 additions & 0 deletions components/switch/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { themr } from 'react-css-themr';
import { switchFactory } from './Switch';
import { SWITCH } from '../identifiers';
import thumbFactory from './Thumb';
import themedRippleFactory from '../ripple';
import theme from './theme.css';

const applyTheme = Component => themr(SWITCH, theme)(Component);
const ripple = themedRippleFactory({ centered: true, spread: 2.6 });
const ThemedThumb = applyTheme(thumbFactory(ripple));
const ThemedSwitch = applyTheme(switchFactory(ThemedThumb));

export default ThemedSwitch;
export { ThemedSwitch as Switch };
132 changes: 132 additions & 0 deletions components/switch/theme.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
@import '../colors.css';
@import '../variables.css';
@import './config.css';

.field {
display: block;
margin-bottom: var(--switch-field-margin-bottom);
position: relative;
white-space: normal;

@apply --reset;
}

.text {
color: var(--switch-text-color);
display: inline-block;
font-size: var(--switch-font-size);
line-height: var(--switch-total-height);
padding-left: var(--unit);
vertical-align: top;
white-space: nowrap;
}

.thumb {
border-radius: 50%;
cursor: pointer;
height: var(--switch-thumb-size);
position: absolute;
top: calc((var(--switch-track-height) - var(--switch-thumb-size)) / 2);
transition-duration: 0.28s;
transition-property: left;
transition-timing-function: var(--animation-curve-default);
width: var(--switch-thumb-size);

@apply --reset;

& .ripple {
background-color: var(--switch-color);
opacity: 0.3;
transition-duration: var(--switch-ripple-duration);
}
}

.on,
.off {
border-radius: var(--switch-track-height);
cursor: pointer;
display: inline-block;
height: var(--switch-track-height);
margin-top: calc((var(--switch-total-height) - var(--switch-track-height)) / 2);
position: relative;
vertical-align: top;
width: var(--switch-track-length);
}

.on {
background: var(--switch-track-on-color);

& .thumb {
background: var(--switch-thumb-on-color);
box-shadow: var(--shadow-3p);
left: calc(var(--switch-track-length) - var(--switch-thumb-size));
}
}

.off {
background: var(--switch-track-off-color);

& .thumb {
background: var(--switch-thumb-off-color);
box-shadow: var(--shadow-2p);
left: 0;
}

& .ripple {
background: var(--switch-off-ripple-color);
}
}

.input {
height: 0;
opacity: 0;
overflow: hidden;
width: 0;

&:focus:not(:active) {
& + .switch-on > .thumb::before,
& + .switch-off > .thumb::before {
background-color: transparent;
border-radius: 50%;
box-sizing: border-box;
content: '';
display: inline-block;
height: var(--switch-focus-init-size);
left: 50%;
position: absolute;
top: 50%;
transform: translate(calc(-1 * var(--switch-focus-init-size) / 2), calc(-1 * var(--switch-focus-init-size) / 2));
width: var(--switch-focus-init-size);
}

& + .switch-on > .thumb::before {
background-color: var(--switch-on-focus-color);
box-shadow: 0 0 0 var(--switch-focus-diff) var(--switch-on-focus-color);
}

& + .switch-off > .thumb::before {
background-color: var(--switch-off-focus-color);
box-shadow: 0 0 0 var(--switch-focus-diff) var(--switch-off-focus-color);
}
}
}

.disabled {
composes: field;

& .text {
color: var(--switch-disabled-text-color);
}

& .on,
& .off {
background: var(--switch-disabled-track-color);
cursor: auto;
}

& .thumb {
background-color: var(--switch-disabled-thumb-color);
border-color: transparent;
cursor: auto;
}
}
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
<div id="root"></div>

<a href="https://github.com/chuangqiTeam/react-cqtoolbox"><img style="position: fixed; top: 0; right: 0; border: 0; z-index: 1000" src="https://camo.githubusercontent.com/e7bbb0521b397edbd5fe43e7f760759336b5e05f/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677265656e5f3030373230302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png"></a>
<script type="text/javascript" src="./manifest.58dc0b70c265fc604d2b.js"></script><script type="text/javascript" src="./main.7dff83cea724915b2c6a.js"></script></body>
<script type="text/javascript" src="./manifest.5b65c10256cc72e84fc3.js"></script><script type="text/javascript" src="./main.207c9ef1a8903c2f0771.js"></script></body>

</html>
25 changes: 25 additions & 0 deletions docs/main.207c9ef1a8903c2f0771.js

Large diffs are not rendered by default.

25 changes: 0 additions & 25 deletions docs/main.7dff83cea724915b2c6a.js

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions src/components/switch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, {Component} from 'react';
import Switch from '../../components/switch';
import Section from '../../components/section';


class SwitchTest extends Component {
state = {
switch_1: true,
switch_2: false,
switch_3: true,
};

handleChange = (field, value) => {
this.setState({ ...this.state, [field]: value });
};

render() {
return (
<Section title="转换开关">
<Switch
checked={this.state.switch_1}
label="微信提醒"
onChange={this.handleChange.bind(this, 'switch_1')}
/>
<Switch
checked={this.state.switch_2}
label="微信提醒"
onChange={this.handleChange.bind(this, 'switch_2')}
/>
<Switch
checked={this.state.switch_3}
disabled
label="禁止"
onChange={this.handleChange.bind(this, 'switch_3')}
/>
</Section>
);
}
}

export default SwitchTest;
2 changes: 2 additions & 0 deletions src/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Select from './components/select';
import Dialog from './components/dialog';
import Input from './components/input';
import InputGroup from './components/input_group';
import Switch from './components/switch';
import Form from './components/form';
import AutoComplete from './components/autocomplete';
import Tooltip from './components/tooltip';
Expand Down Expand Up @@ -40,6 +41,7 @@ class Root extends Component {
<Dialog />
<Input />
<InputGroup />
<Switch />
<Form />
<AutoComplete />
<Tooltip />
Expand Down

0 comments on commit 33cd421

Please sign in to comment.