DropdownButton.jsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. // @flow
  15. import React from 'react'
  16. import styled, { css } from 'styled-components'
  17. import arrowImage from './images/arrow.js'
  18. import Palette from '../../styleUtils/Palette'
  19. import StyleProps from '../../styleUtils/StyleProps'
  20. const getLabelColor = props => {
  21. if (props.disabled) {
  22. return Palette.grayscale[3]
  23. }
  24. if (props.primary) {
  25. return 'white'
  26. }
  27. return Palette.black
  28. }
  29. const Label = styled.div`
  30. color: ${props => getLabelColor(props)};
  31. margin: 0 32px 0 16px;
  32. overflow: hidden;
  33. text-overflow: ellipsis;
  34. white-space: nowrap;
  35. flex-grow: 1;
  36. ${props => props.useBold ? `font-weight: ${StyleProps.fontWeights.medium};` : ''}
  37. ${props => props.centered ? 'text-align: center;' : ''}
  38. `
  39. const getBackgroundColor = props => {
  40. if (props.disabled) {
  41. return Palette.grayscale[0]
  42. }
  43. if (props.primary) {
  44. return Palette.primary
  45. }
  46. return 'white'
  47. }
  48. const getArrowColor = props => {
  49. if (props.disabled) {
  50. return Palette.grayscale[0]
  51. }
  52. if (props.primary) {
  53. return 'white'
  54. }
  55. return Palette.grayscale[4]
  56. }
  57. const getWidth = props => {
  58. if (props.large) {
  59. return StyleProps.inputSizes.large.width - 2
  60. }
  61. if (props.width) {
  62. return props.width - 2
  63. }
  64. return StyleProps.inputSizes.regular.width - 2
  65. }
  66. const borderColor = props => {
  67. if (props.highlight) {
  68. return Palette.alert
  69. }
  70. if (props.disabled) {
  71. return Palette.grayscale[0]
  72. }
  73. if (props.primary) {
  74. return Palette.primary
  75. }
  76. return Palette.grayscale[3]
  77. }
  78. const Wrapper = styled.div`
  79. display: flex;
  80. align-items: center;
  81. position: relative;
  82. width: ${props => getWidth(props)}px;
  83. height: ${props => props.large ? StyleProps.inputSizes.large.height - 2
  84. : StyleProps.inputSizes.regular.height - 2}px;
  85. border: 1px solid ${props => borderColor(props)};
  86. border-radius: ${StyleProps.borderRadius};
  87. cursor: ${props => props.disabled ? 'default' : 'pointer'};
  88. transition: all ${StyleProps.animations.swift};
  89. background: ${props => getBackgroundColor(props)};
  90. ${props => props.embedded ? css`
  91. border: 0;
  92. width: calc(100% + 8px);
  93. margin-left: -16px;
  94. ` : ''}
  95. #dropdown-arrow-image {stroke: ${props => getArrowColor(props)};}
  96. &:hover {
  97. #dropdown-arrow-image {stroke: ${props => props.disabled ? '' : props.embedded ? '' : 'white'};}
  98. background: ${props => props.disabled ? '' : props.embedded ? '' : Palette.primary};
  99. }
  100. &:hover ${Label} {
  101. color: ${props => props.disabled ? '' : props.embedded ? '' : 'white'};
  102. }
  103. `
  104. const Arrow = styled.div`
  105. position: absolute;
  106. right: 8px;
  107. top: 12px;
  108. display: flex;
  109. `
  110. type Props = {
  111. value: string,
  112. onClick?: (event: Event) => void,
  113. customRef?: (ref: HTMLElement) => void,
  114. innerRef?: (ref: HTMLElement) => void,
  115. className?: string,
  116. disabled?: boolean,
  117. 'data-test-id'?: string,
  118. embedded?: boolean,
  119. highlight?: boolean,
  120. }
  121. class DropdownButton extends React.Component<Props> {
  122. render() {
  123. return (
  124. <Wrapper
  125. data-test-id={this.props['data-test-id'] || 'dropdownButton'}
  126. {...this.props}
  127. innerRef={e => {
  128. if (this.props.customRef) {
  129. this.props.customRef(e)
  130. } else if (this.props.innerRef) {
  131. this.props.innerRef(e)
  132. }
  133. }}
  134. onClick={e => { if (!this.props.disabled && this.props.onClick) this.props.onClick(e) }}
  135. >
  136. <Label
  137. {...this.props}
  138. onClick={() => { }}
  139. innerRef={() => { }}
  140. data-test-id="dropdownButton-value"
  141. disabled={this.props.disabled}
  142. >
  143. {this.props.value}
  144. </Label>
  145. <Arrow
  146. {...this.props}
  147. innerRef={() => { }}
  148. onClick={() => { }}
  149. data-test-id=""
  150. disabled={this.props.disabled}
  151. dangerouslySetInnerHTML={{ __html: arrowImage }}
  152. />
  153. </Wrapper>
  154. )
  155. }
  156. }
  157. export default DropdownButton