├── .babelrc ├── webpack.config.js ├── .gitignore ├── test ├── helpers │ └── fakeDom.js └── Switch-test.js ├── src ├── utils.js ├── Label.js └── Switch.js ├── example ├── index.html ├── example.css └── example.js ├── lib ├── utils.js ├── Label.js └── Switch.js ├── CHANGELOG.md ├── package.json └── README.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | 3 | module.exports = { 4 | entry: { 5 | example: ['./example/example.js'] 6 | }, 7 | module: { 8 | loaders: [ 9 | { 10 | test: /\.js/, 11 | loader: 'babel-loader' 12 | } 13 | ] 14 | }, 15 | output: { 16 | path: path.resolve(__dirname, 'example'), 17 | publicPath: '/example', 18 | filename: 'bundle.js' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Coverage tools 11 | lib-cov 12 | coverage 13 | coverage.html 14 | .cover* 15 | 16 | # Dependency directory 17 | node_modules 18 | package-lock.json 19 | 20 | # Example build directory 21 | example/dist 22 | .publish 23 | 24 | # Editor and other tmp files 25 | *.swp 26 | *.un~ 27 | *.iml 28 | *.ipr 29 | *.iws 30 | *.sublime-* 31 | .idea/ 32 | *.DS_Store 33 | -------------------------------------------------------------------------------- /test/helpers/fakeDom.js: -------------------------------------------------------------------------------- 1 | const jsdom = require('jsdom'); 2 | const doc = jsdom.jsdom('
'); 3 | const win = doc.defaultView; 4 | 5 | global.document = doc; 6 | global.window = win; 7 | global.navigator = {userAgent: 'node.js'}; 8 | 9 | propagateToGlobal(win); 10 | 11 | function propagateToGlobal (window) { 12 | for (let key in window) { 13 | if (!window.hasOwnProperty(key)) continue; 14 | if (key in global) continue; 15 | 16 | global[key] = window[key]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | export const events = { 2 | touch: { 3 | start: 'touchstart', 4 | stop: 'touchend', 5 | move: 'touchmove' 6 | }, 7 | mouse: { 8 | start: 'mousedown', 9 | stop: 'mouseup' 10 | } 11 | }; 12 | 13 | export function merge(...hashes) { 14 | return Object.assign({}, ...hashes); 15 | } 16 | 17 | export function disableScroll() { 18 | document.addEventListener(events.touch.move, preventScroll, false); 19 | } 20 | 21 | export function reEnableScroll() { 22 | document.removeEventListener(events.touch.move, preventScroll, false); 23 | } 24 | 25 | function preventScroll(e) { 26 | e.preventDefault(); 27 | } 28 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Flexible Switch 4 | 5 | 6 | 7 | 8 |
9 |

React Flexible Switch

10 |

View project on GitHub

11 |
12 |
13 | 14 |
15 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Label.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { merge } from './utils' 3 | import PropTypes from 'prop-types' 4 | 5 | export default class Label extends PureComponent { 6 | styles() { 7 | const offset = this.props.active ? { left: '20% ' } : { right: '20%' } 8 | 9 | return merge( 10 | { 11 | position: 'absolute', 12 | top: '50%', 13 | transform: 'translateY(-50%)', 14 | pointerEvents: 'none' 15 | }, 16 | offset 17 | ) 18 | } 19 | 20 | render() { 21 | return ( 22 | 23 | {this.props.active ? this.props.labels.on : this.props.labels.off} 24 | 25 | ) 26 | } 27 | } 28 | 29 | Label.propTypes = { 30 | active: PropTypes.bool, 31 | labels: PropTypes.shape({ 32 | on: PropTypes.string.isRequired, 33 | off: PropTypes.string.isRequired 34 | }).isRequired 35 | } 36 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.merge = merge; 7 | exports.disableScroll = disableScroll; 8 | exports.reEnableScroll = reEnableScroll; 9 | var events = exports.events = { 10 | touch: { 11 | start: 'touchstart', 12 | stop: 'touchend', 13 | move: 'touchmove' 14 | }, 15 | mouse: { 16 | start: 'mousedown', 17 | stop: 'mouseup' 18 | } 19 | }; 20 | 21 | function merge() { 22 | for (var _len = arguments.length, hashes = Array(_len), _key = 0; _key < _len; _key++) { 23 | hashes[_key] = arguments[_key]; 24 | } 25 | 26 | return Object.assign.apply(Object, [{}].concat(hashes)); 27 | } 28 | 29 | function disableScroll() { 30 | document.addEventListener(events.touch.move, preventScroll, false); 31 | } 32 | 33 | function reEnableScroll() { 34 | document.removeEventListener(events.touch.move, preventScroll, false); 35 | } 36 | 37 | function preventScroll(e) { 38 | e.preventDefault(); 39 | } -------------------------------------------------------------------------------- /example/example.css: -------------------------------------------------------------------------------- 1 | /* 2 | // Examples Stylesheet 3 | // ------------------- 4 | */ 5 | 6 | body { 7 | font-family: Helvetica Neue, Helvetica, Arial, sans-serif; 8 | font-size: 14px; 9 | color: #333; 10 | margin: 0; 11 | padding: 0; 12 | } 13 | 14 | a { 15 | color: #08c; 16 | text-decoration: none; 17 | } 18 | 19 | a:hover { 20 | text-decoration: underline; 21 | } 22 | 23 | .container { 24 | margin-left: auto; 25 | margin-right: auto; 26 | max-width: 720px; 27 | padding: 1em; 28 | } 29 | 30 | .footer { 31 | margin-top: 50px; 32 | border-top: 1px solid #eee; 33 | padding: 20px 0; 34 | font-size: 12px; 35 | color: #999; 36 | } 37 | 38 | h1, 39 | h2, 40 | h3, 41 | h4, 42 | h5, 43 | h6 { 44 | color: #222; 45 | font-weight: 100; 46 | margin: 0.5em 0; 47 | } 48 | 49 | label { 50 | color: #999; 51 | display: inline-block; 52 | font-size: 0.85em; 53 | font-weight: bold; 54 | margin: 1em 0; 55 | text-transform: uppercase; 56 | } 57 | 58 | .hint { 59 | margin: 15px 0; 60 | font-style: italic; 61 | color: #999; 62 | } 63 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## 1.2.0 (Nov 21, 2017) 5 | ### Added 6 | - Add support for React 16 7 | 8 | ## 1.1.0 (Apr 5, 2017) 9 | ### Added 10 | - Add namespaced CSS class for the circle component 11 | 12 | ## 1.0.1 (Apr 5, 2017) 13 | ### Fixed 14 | - Updated CHANGELOG to mention 1.0.0 15 | 16 | ## 1.0.0 (Apr 5, 2017) 17 | ### Added 18 | - Namespace CSS classes in order to avoid colisions 19 | 20 | ## 0.6.0 (Jan 9, 2017) 21 | ### Added 22 | - Add keyboard access support 23 | 24 | ## 0.5.1 (Nov 26, 2016) 25 | ### Fixed 26 | - Fixed wrong reference to `value` in Readme 27 | 28 | ## 0.5.0 (Nov 26, 2016) 29 | ### Added 30 | - Make Switch a controlled component 31 | 32 | ### Breaking Changes 33 | - Remove `active` and `inactive` in favor of using `value` as the controlling property 34 | - Remove `onActive` and `onInactive` in favor of using `onChange` 35 | 36 | ## 0.4.1 (Sep 24, 2016) 37 | ### Added 38 | - Support for React 15 (peer dependency) 39 | 40 | ## 0.3.1 (Jun 30, 2016) 41 | 42 | ### Bug Fixes 43 | - Reset global events when `locked` props are changed 44 | - Only enable touch events when necessary 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-flexible-switch", 3 | "version": "1.2.1", 4 | "description": "Simple and flexible React Switch", 5 | "main": "lib/Switch.js", 6 | "author": "Netto Farah", 7 | "homepage": "https://github.com/nettofarah/react-flexible-switch", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/nettofarah/react-flexible-switch.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/nettofarah/react-flexible-switch/issues" 14 | }, 15 | "dependencies": { 16 | "classnames": "^2.1.2", 17 | "prop-types": "^15.6.0" 18 | }, 19 | "devDependencies": { 20 | "babel-cli": "^6.26.0", 21 | "babel-core": "^6.26.0", 22 | "babel-loader": "^7.1.2", 23 | "babel-preset-es2015": "^6.24.1", 24 | "babel-preset-react": "^6.24.1", 25 | "branchsite": "^4.0.2", 26 | "jsdom": "^8.4.0", 27 | "mocha": "^2.4.5", 28 | "np": "^2.17.0", 29 | "react": "^16.1.1", 30 | "react-dom": "^16.1.1", 31 | "webpack": "^3.8.1", 32 | "webpack-dev-server": "^2.9.4" 33 | }, 34 | "peerDependencies": { 35 | "react": "^0.14 || ^15.0.0-rc || ^15.0 || ^16.0", 36 | "react-dom": "^0.14 || ^15.0.0-rc || ^15.0 || ^16.0" 37 | }, 38 | "browserify-shim": { 39 | "react": "global:React" 40 | }, 41 | "scripts": { 42 | "build": "babel src -d lib", 43 | "test": 44 | "NODE_ENV=test mocha --compilers js:babel-register --require ./test/helpers/fakeDom.js", 45 | "dev": "webpack-dev-server", 46 | "build-example": "webpack", 47 | "release": "np --yolo" 48 | }, 49 | "keywords": [ 50 | "react", 51 | "react-component", 52 | "switch", 53 | "toggle", 54 | "react-switch", 55 | "react-toggle" 56 | ], 57 | "files": ["lib", "src"] 58 | } 59 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import Switch from '../lib/Switch' 4 | 5 | class App extends React.Component { 6 | constructor() { 7 | super() 8 | this.state = { locked: true, externalValue: true } 9 | } 10 | 11 | render() { 12 | return ( 13 |
14 |

On By default

15 | 16 | 17 |

Off By default

18 | 19 | 20 |

Custom Colors

21 | 22 | 23 |

Custom Diameter

24 | 25 |
26 | 27 | 28 |

Custom Switch Width

29 | 30 |
31 | 32 | 33 |

Labels

34 | 35 | 36 |

Locking the Switch

37 | 40 | 43 |
44 |
45 | 46 | 47 |
48 | 49 |

External Controls

50 | 57 |
58 |
59 | 60 | { 64 | this.setState({ externalValue: value }) 65 | }} 66 | /> 67 |
68 | { 72 | this.setState({ externalValue: !value }) 73 | }} 74 | /> 75 |
76 | ) 77 | } 78 | } 79 | 80 | ReactDOM.render(, document.getElementById('app')) 81 | -------------------------------------------------------------------------------- /lib/Label.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 8 | 9 | var _react = require('react'); 10 | 11 | var _react2 = _interopRequireDefault(_react); 12 | 13 | var _utils = require('./utils'); 14 | 15 | var _propTypes = require('prop-types'); 16 | 17 | var _propTypes2 = _interopRequireDefault(_propTypes); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 22 | 23 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 24 | 25 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 26 | 27 | var Label = function (_PureComponent) { 28 | _inherits(Label, _PureComponent); 29 | 30 | function Label() { 31 | _classCallCheck(this, Label); 32 | 33 | return _possibleConstructorReturn(this, (Label.__proto__ || Object.getPrototypeOf(Label)).apply(this, arguments)); 34 | } 35 | 36 | _createClass(Label, [{ 37 | key: 'styles', 38 | value: function styles() { 39 | var offset = this.props.active ? { left: '20% ' } : { right: '20%' }; 40 | 41 | return (0, _utils.merge)({ 42 | position: 'absolute', 43 | top: '50%', 44 | transform: 'translateY(-50%)', 45 | pointerEvents: 'none' 46 | }, offset); 47 | } 48 | }, { 49 | key: 'render', 50 | value: function render() { 51 | return _react2.default.createElement( 52 | 'span', 53 | { style: this.styles(), className: 'react-flexible-switch-label' }, 54 | this.props.active ? this.props.labels.on : this.props.labels.off 55 | ); 56 | } 57 | }]); 58 | 59 | return Label; 60 | }(_react.PureComponent); 61 | 62 | exports.default = Label; 63 | 64 | 65 | Label.propTypes = { 66 | active: _propTypes2.default.bool, 67 | labels: _propTypes2.default.shape({ 68 | on: _propTypes2.default.string.isRequired, 69 | off: _propTypes2.default.string.isRequired 70 | }).isRequired 71 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Flexible Switch 2 | Easy and Flexible React switches with support for custom styles. 3 | 4 | 5 | ## Demo & Examples 6 | 7 | ![switch](https://cloud.githubusercontent.com/assets/270688/14726482/870deed8-07d7-11e6-9c78-be337a1159f0.gif) 8 | 9 | Live demo: [http://nettofarah.github.io/react-flexible-switch](http://nettofarah.github.io/react-flexible-switch/) 10 | To build the examples locally, run: 11 | 12 | ```bash 13 | npm install 14 | npm start 15 | ``` 16 | 17 | Then open [`localhost:8000`](http://localhost:8000) in a browser. 18 | 19 | 20 | ## Installation 21 | 22 | The easiest way to use react-switch is to install it from NPM and include it in your own React build process (using [Browserify](http://browserify.org), [Webpack](http://webpack.github.io/), etc). 23 | 24 | You can also use the standalone build by including `dist/react-switch.js` in your page. If you use this, make sure you have already included React, and it is available as a global variable. 25 | 26 | ``` 27 | npm install react-flexible-switch --save 28 | ``` 29 | 30 | 31 | ## Usage 32 | 33 | Just require 'react-flexible-switch' in your app and include it in your components. 34 | 35 | ```javascript 36 | const Switch = require('react-flexible-switch'); 37 | 38 | ``` 39 | 40 | ### Properties 41 | 42 | ```javascript 43 | Switch.propTypes = { 44 | value: React.PropTypes.bool, 45 | 46 | circleStyles: React.PropTypes.shape({ 47 | onColor: React.PropTypes.string, 48 | offColor: React.PropTypes.string, 49 | diameter: React.PropTypes.number 50 | }), 51 | 52 | labels: React.PropTypes.shape({ 53 | on: React.PropTypes.string, 54 | off: React.PropTypes.string 55 | }), 56 | 57 | locked: React.PropTypes.bool, 58 | 59 | onChange: React.PropTypes.func, 60 | 61 | switchStyles: React.PropTypes.shape({ 62 | width: React.PropTypes.number 63 | }) 64 | }; 65 | ``` 66 | 67 | #### value 68 | Allows you to start a switch either turned on or off. 69 | 70 | ```javascript 71 | //On by default 72 | 73 | 74 | //Off by default 75 | 76 | ``` 77 | 78 | #### onChange 79 | Allows you to pass in callback for when state changes. 80 | This will allow you to make the switch a controlled component. 81 | 82 | ```javascript 83 | const onChange = (active) => { 84 | if (active) { 85 | console.log('active!') 86 | } else { 87 | console.log('inactive!') 88 | } 89 | 90 | // update your state here 91 | this.setState({ value: active }) 92 | } 93 | 94 | 95 | ``` 96 | 97 | #### Custom Styles 98 | You can style both the circle and switch styles with any css property, with 99 | the addition of `onColor`, `offColor` and `diameter`. 100 | 101 | 102 | ```javascript 103 | // Custom circle colors and size 104 | 105 | 106 | 107 | 108 | // Custom Switch width 109 | 110 | 111 | ``` 112 | 113 | #### Customzing with CSS classes 114 | You can also style the components using the following css classes: 115 | 116 | - `react-flexible-switch`: the main component 117 | - `react-flexible-switch--active`: the main component, when active 118 | - `react-flexible-switch--inactive`: the main component, when inactive 119 | - `react-flexible-switch--sliding`: the main component, during the transition 120 | - `react-flexible-switch-label`: the label component 121 | - `react-flexible-switch-circle`: the circle component 122 | 123 | #### Labels 124 | Labels for the `on` and `off` states can be set by using the `labels` property. 125 | 126 | ```javascript 127 | 128 | 129 | ``` 130 | 131 | #### Blocking User Interaction 132 | In case you need to lock the switch and block user interaction for some reason. 133 | 134 | ```javascript 135 | 136 | 137 | ``` 138 | 139 | ## Development (`src`, `lib` and the build process) 140 | 141 | **NOTE:** The source code for the component is in `src`. A transpiled CommonJS version (generated with Babel) is available in `lib` for use with node.js, browserify and webpack. A UMD bundle is also built to `dist`, which can be included without the need for any build system. 142 | 143 | To build, watch and serve the examples (which will also watch the component source), run `npm start`. If you just want to watch changes to `src` and rebuild `lib`, run `npm run watch` (this is useful if you are working with `npm link`). 144 | 145 | ## License 146 | The module is available as open source under the terms of the MIT License. 147 | Copyright (c) 2016 Netto Farah. 148 | -------------------------------------------------------------------------------- /src/Switch.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import classNames from 'classnames' 3 | import Label from './Label' 4 | import { merge, events, disableScroll, reEnableScroll } from './utils' 5 | import PropTypes from 'prop-types' 6 | 7 | class Switch extends React.Component { 8 | constructor(props) { 9 | super(props) 10 | 11 | this.onActivateButton = this.onActivateButton.bind(this) 12 | this.onSlideEnd = this.onSlideEnd.bind(this) 13 | this.onSlideStart = this.onSlideStart.bind(this) 14 | this.onMouseLeave = this.onMouseLeave.bind(this) 15 | 16 | this.isTouchDevice = window['ontouchstart'] !== undefined 17 | 18 | this.state = { sliding: false, value: this.props.value } 19 | } 20 | 21 | componentDidMount() { 22 | this.addListener() 23 | } 24 | 25 | componentWillReceiveProps(nextProps) { 26 | if (nextProps.value === undefined) { 27 | return 28 | } 29 | 30 | if (nextProps.value !== this.state.value) { 31 | this.setState({ value: nextProps.value }) 32 | } 33 | } 34 | 35 | componentDidUpdate(prevProps, prevState) { 36 | if (this.state.value != prevState.value) { 37 | this.props.onChange(this.state.value) 38 | } 39 | } 40 | 41 | componentWillUnmount() { 42 | this.removeListener() 43 | } 44 | 45 | addListener() { 46 | if (this.isTouchDevice) { 47 | document.addEventListener(events.touch.start, this.onSlideStart, false) 48 | document.addEventListener(events.touch.stop, this.onSlideEnd, false) 49 | } else { 50 | document.addEventListener(events.mouse.start, this.onSlideStart, false) 51 | document.addEventListener(events.mouse.stop, this.onSlideEnd, false) 52 | } 53 | } 54 | 55 | removeListener() { 56 | if (this.isTouchDevice) { 57 | document.removeEventListener(events.touch.start, this.onSlideStart, false) 58 | document.removeEventListener(events.touch.stop, this.onSlideEnd, false) 59 | } else { 60 | document.removeEventListener(events.mouse.start, this.onSlideStart, false) 61 | document.removeEventListener(events.mouse.stop, this.onSlideEnd, false) 62 | } 63 | } 64 | 65 | onActivateButton() { 66 | this.setState({ value: !this.state.value }) 67 | } 68 | 69 | onSlideEnd() { 70 | if (this.props.locked) { 71 | return 72 | } 73 | 74 | if (this.state.sliding) { 75 | this.setState({ sliding: false, value: !this.state.value }) 76 | reEnableScroll() 77 | } 78 | } 79 | 80 | onSlideStart(e) { 81 | if (this.props.locked) { 82 | return 83 | } 84 | 85 | if (e.target == this.refs.circle || e.target == this.refs.switch) { 86 | this.setState({ sliding: true }) 87 | disableScroll() 88 | } 89 | } 90 | 91 | onMouseLeave(e) { 92 | this.onSlideEnd(e) 93 | } 94 | 95 | classes() { 96 | return classNames( 97 | 'react-flexible-switch', 98 | { 'react-flexible-switch--sliding': this.state.sliding }, 99 | { 'react-flexible-switch--active': this.state.value }, 100 | { 'react-flexible-switch--inactive': !this.state.value } 101 | ) 102 | } 103 | 104 | switchStyles() { 105 | const switchStyles = this.switchStylesProps() 106 | return merge({ borderRadius: switchStyles.width / 2 }, switchStyles) 107 | } 108 | 109 | translationStyle() { 110 | const circleStyles = this.circleStylesProps() 111 | const switchStyles = this.switchStyles() 112 | 113 | const offset = switchStyles.width - circleStyles.diameter 114 | let translation = this.state.value ? offset : 0 115 | 116 | if (this.state.sliding && this.state.value) { 117 | translation -= circleStyles.diameter / 4 + switchStyles.padding / 4 118 | } 119 | 120 | return { 121 | transform: `translateX(${translation}px)` 122 | } 123 | } 124 | 125 | backgroundStyle() { 126 | const circleStyles = this.circleStylesProps() 127 | const backgroundColor = this.state.value 128 | ? circleStyles.onColor 129 | : circleStyles.offColor 130 | return { backgroundColor } 131 | } 132 | 133 | circleStylesProps() { 134 | return merge(defaultCircleStyles, this.props.circleStyles) 135 | } 136 | 137 | switchStylesProps() { 138 | return merge(defaultSwitchStyles, this.props.switchStyles) 139 | } 140 | 141 | circleDimensionsStyle() { 142 | const switchStyles = this.switchStyles() 143 | const circleStyles = this.circleStylesProps() 144 | const width = this.state.sliding 145 | ? circleStyles.diameter + circleStyles.diameter / 4 146 | : circleStyles.diameter 147 | return { width, height: circleStyles.diameter } 148 | } 149 | 150 | circleStyles() { 151 | return merge( 152 | this.circleDimensionsStyle(), 153 | this.backgroundStyle(), 154 | this.translationStyle(), 155 | this.circleStylesProps() 156 | ) 157 | } 158 | 159 | render() { 160 | return ( 161 | 167 |