| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /*
- Copyright (C) 2017 Cloudbase Solutions SRL
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- // @flow
- import React from 'react'
- import { observer } from 'mobx-react'
- import styled from 'styled-components'
- import Palette from '../../styleUtils/Palette'
- import StyleProps from '../../styleUtils/StyleProps'
- const Wrapper = styled.div`
- display: flex;
- height: ${StyleProps.inputSizes.regular.height}px;
- align-items: center;
- ${props => props.disabled ? 'opacity: 0.5;' : ''}
- ${props => props.justifyContent ? `justify-content: ${props.justifyContent};` : ''}
- ${props => props.width ? `width: ${props.width};` : ''}
- `
- const InputWrapper = styled.div`
- position: relative;
- width: ${props => props.height * 2}px;
- height: ${props => props.height}px;
- ${props => !props.disabled ? 'cursor: pointer;' : ''};
- `
- const inputBackground = props => {
- if (props.big) {
- if (props.checked) {
- return Palette.alert
- }
- return Palette.primary
- }
- if (props.secondary && props.checked) {
- return Palette.grayscale[5]
- }
- if (props.checked) {
- return Palette.primary
- }
- return 'white'
- }
- const getInputBorderColor = props => {
- if (props.big && props.checked) {
- return Palette.alert
- }
- if (props.secondary) {
- return Palette.grayscale[5]
- }
- if (props.triState && props.checked == null) {
- return Palette.grayscale[2]
- }
- return Palette.primary
- }
- const InputBackground = styled.div`
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- transition: all ${StyleProps.animations.swift};
- background: ${props => inputBackground(props)};
- border-radius: 50px;
- border: 1px solid ${props => getInputBorderColor(props)};
- `
- const getThumbLeft = props => {
- if (props.checked) {
- return props.height - 1
- }
- if (props.triState && props.checked == null) {
- return (props.height / 2) - 1
- }
- return -1
- }
- const InputThumb = styled.div`
- position: absolute;
- width: ${props => props.height - 2}px;
- height: ${props => props.height - 2}px;
- transition: all ${StyleProps.animations.swift};
- top: -1px;
- left: ${props => getThumbLeft(props)}px;
- background: white;
- border: 1px solid ${props => getInputBorderColor(props)};
- border-radius: 50%;
- `
- const Label = styled.div`
- margin-left: 16px;
- ${props => props.secondary ? `color: ${Palette.grayscale[4]};` : ''}
- white-space: nowrap;
- `
- const LeftLabel = styled.div`
- margin-right: 16px;
- color: ${Palette.grayscale[4]};
- white-space: nowrap;
- `
- type Props = {
- onChange: (checked: ?boolean) => void,
- checked: boolean,
- disabled: boolean,
- triState: boolean,
- leftLabel: boolean,
- secondary: boolean,
- noLabel: boolean,
- height: number,
- width: string,
- justifyContent: string,
- big: boolean,
- checkedLabel: string,
- uncheckedLabel: string,
- 'data-test-id'?: string,
- style: { [string]: mixed },
- }
- type State = {
- lastChecked: ?boolean,
- }
- @observer
- class Switch extends React.Component<Props, State> {
- static defaultProps: $Shape<Props> = {
- checkedLabel: 'Yes',
- uncheckedLabel: 'No',
- height: 24,
- }
- state = {
- lastChecked: null,
- }
- getLabel() {
- let label = this.props.checked ? this.props.checkedLabel : this.props.uncheckedLabel
- if (this.props.triState && this.props.checked == null) {
- label = 'Not Set'
- }
- return label
- }
- handleInputChange() {
- if (this.props.disabled) {
- return
- }
- if (this.props.triState) {
- if (this.props.checked === true || this.props.checked === false) {
- this.setState({ lastChecked: this.props.checked })
- this.props.onChange(null)
- } else {
- this.props.onChange(!this.state.lastChecked)
- }
- } else {
- this.props.onChange(!this.props.checked)
- }
- }
- renderInput() {
- return (
- <InputWrapper
- triState={this.props.triState}
- big={this.props.big}
- height={this.props.height}
- secondary={this.props.secondary}
- disabled={this.props.disabled}
- onClick={() => { this.handleInputChange() }}
- data-test-id={this.props['data-test-id'] || 'switch-input'}
- >
- <InputBackground
- triState={this.props.triState}
- big={this.props.big}
- checked={this.props.checked}
- height={this.props.height}
- secondary={this.props.secondary}
- >
- <InputThumb
- triState={this.props.triState}
- big={this.props.big}
- checked={this.props.checked}
- height={this.props.height}
- secondary={this.props.secondary}
- />
- </InputBackground>
- </InputWrapper>
- )
- }
- renderLeftLabel() {
- if (!this.props.leftLabel || this.props.noLabel) {
- return null
- }
- return (
- <LeftLabel>{this.getLabel()}</LeftLabel>
- )
- }
- renderRightLabel() {
- if (this.props.big || this.props.leftLabel || this.props.noLabel) {
- return null
- }
- return (
- <Label secondary={this.props.secondary}>{this.getLabel()}</Label>
- )
- }
- render() {
- return (
- <Wrapper
- disabled={this.props.disabled}
- style={this.props.style}
- width={this.props.width}
- justifyContent={this.props.justifyContent}
- >
- {this.renderLeftLabel()}
- {this.renderInput()}
- {this.renderRightLabel()}
- </Wrapper>
- )
- }
- }
- export default Switch
|