DropdownButton.jsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 || props.secondary) {
  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.secondary) {
  44. return Palette.secondaryLight
  45. }
  46. if (props.primary) {
  47. return Palette.primary
  48. }
  49. return 'white'
  50. }
  51. const getArrowColor = props => {
  52. if (props.disabled) {
  53. return Palette.grayscale[3]
  54. }
  55. if (props.primary || props.secondary) {
  56. return 'white'
  57. }
  58. return Palette.black
  59. }
  60. const getWidth = props => {
  61. if (props.large) {
  62. return StyleProps.inputSizes.large.width - 2
  63. }
  64. if (props.width) {
  65. return props.width - 2
  66. }
  67. return StyleProps.inputSizes.regular.width - 2
  68. }
  69. const borderColor = props => {
  70. if (props.highlight) {
  71. return Palette.alert
  72. }
  73. if (props.disabled) {
  74. return Palette.grayscale[0]
  75. }
  76. if (props.primary) {
  77. return Palette.primary
  78. }
  79. if (props.secondary) {
  80. return Palette.secondaryLight
  81. }
  82. return Palette.grayscale[3]
  83. }
  84. const backgroundHover = props => {
  85. if (props.disabled || props.embedded) {
  86. return ''
  87. }
  88. if (props.secondary) {
  89. return Palette.secondaryLight
  90. }
  91. return Palette.primary
  92. }
  93. const Wrapper = styled.div`
  94. display: flex;
  95. align-items: center;
  96. position: relative;
  97. width: ${props => getWidth(props)}px;
  98. height: ${props => props.large ? StyleProps.inputSizes.large.height - 2
  99. : StyleProps.inputSizes.regular.height - 2}px;
  100. border: 1px solid ${props => borderColor(props)};
  101. border-radius: ${StyleProps.borderRadius};
  102. cursor: ${props => props.disabled ? 'default' : 'pointer'};
  103. transition: all ${StyleProps.animations.swift};
  104. background: ${props => getBackgroundColor(props)};
  105. ${props => props.embedded ? css`
  106. border: 0;
  107. width: calc(100% + 8px);
  108. margin-left: -16px;
  109. ` : ''}
  110. #dropdown-arrow-image {stroke: ${props => getArrowColor(props)};}
  111. &:hover {
  112. #dropdown-arrow-image {stroke: ${props => props.disabled ? '' : props.embedded ? '' : 'white'};}
  113. background: ${props => backgroundHover(props)};
  114. }
  115. &:hover ${Label} {
  116. color: ${props => props.disabled ? '' : props.embedded ? '' : 'white'};
  117. }
  118. `
  119. const Arrow = styled.div`
  120. position: absolute;
  121. right: 8px;
  122. top: 8px;
  123. display: flex;
  124. width: 16px;
  125. height: 16px;
  126. justify-content: center;
  127. align-items: center;
  128. `
  129. type Props = {
  130. value: string,
  131. onClick?: (event: Event) => void,
  132. customRef?: (ref: HTMLElement) => void,
  133. innerRef?: (ref: HTMLElement) => void,
  134. arrowRef?: (ref: HTMLElement) => void,
  135. className?: string,
  136. disabled?: boolean,
  137. 'data-test-id'?: string,
  138. embedded?: boolean,
  139. highlight?: boolean,
  140. secondary?: boolean,
  141. centered?: boolean,
  142. }
  143. class DropdownButton extends React.Component<Props> {
  144. render() {
  145. return (
  146. <Wrapper
  147. data-test-id={this.props['data-test-id'] || 'dropdownButton'}
  148. {...this.props}
  149. innerRef={e => {
  150. if (this.props.customRef) {
  151. this.props.customRef(e)
  152. } else if (this.props.innerRef) {
  153. this.props.innerRef(e)
  154. }
  155. }}
  156. onClick={e => { if (!this.props.disabled && this.props.onClick) this.props.onClick(e) }}
  157. >
  158. <Label
  159. {...this.props}
  160. onClick={() => { }}
  161. innerRef={() => { }}
  162. data-test-id="dropdownButton-value"
  163. disabled={this.props.disabled}
  164. >
  165. {this.props.value}
  166. </Label>
  167. <Arrow
  168. {...this.props}
  169. innerRef={ref => { if (this.props.arrowRef) this.props.arrowRef(ref) }}
  170. onClick={() => { }}
  171. data-test-id=""
  172. disabled={this.props.disabled}
  173. dangerouslySetInnerHTML={{ __html: arrowImage }}
  174. />
  175. </Wrapper>
  176. )
  177. }
  178. }
  179. export default DropdownButton