Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

Select.tsx 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import React, { ChangeEvent } from 'react';
  2. import { makeStyles } from 'tss-react/mui';
  3. import { isMobileBrowser } from '../../../environment/utils';
  4. import Icon from '../../../icons/components/Icon';
  5. import { IconArrowDown } from '../../../icons/svg';
  6. import { withPixelLineHeight } from '../../../styles/functions.web';
  7. interface ISelectProps {
  8. /**
  9. * Helper text to be displayed below the select.
  10. */
  11. bottomLabel?: string;
  12. /**
  13. * Class name for additional styles.
  14. */
  15. className?: string;
  16. /**
  17. * Wether or not the select is disabled.
  18. */
  19. disabled?: boolean;
  20. /**
  21. * Wether or not the select is in the error state.
  22. */
  23. error?: boolean;
  24. /**
  25. * Label to be displayed above the select.
  26. */
  27. label?: string;
  28. /**
  29. * Change handler.
  30. */
  31. onChange: (e: ChangeEvent<HTMLSelectElement>) => void;
  32. /**
  33. * The options of the select.
  34. */
  35. options: Array<{
  36. label: string;
  37. value: number | string;
  38. }>;
  39. /**
  40. * The value of the select.
  41. */
  42. value: number | string;
  43. }
  44. const useStyles = makeStyles()(theme => {
  45. return {
  46. container: {
  47. display: 'flex',
  48. flexDirection: 'column'
  49. },
  50. label: {
  51. color: theme.palette.text01,
  52. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  53. marginBottom: theme.spacing(2),
  54. '&.is-mobile': {
  55. ...withPixelLineHeight(theme.typography.bodyShortRegularLarge)
  56. }
  57. },
  58. selectContainer: {
  59. position: 'relative'
  60. },
  61. select: {
  62. backgroundColor: theme.palette.ui03,
  63. borderRadius: `${theme.shape.borderRadius}px`,
  64. width: '100%',
  65. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  66. color: theme.palette.text01,
  67. padding: '8px 16px',
  68. paddingRight: '42px',
  69. border: 0,
  70. appearance: 'none',
  71. overflow: 'hidden',
  72. whiteSpace: 'nowrap',
  73. textOverflow: 'ellipsis',
  74. '&:focus': {
  75. outline: 0,
  76. boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
  77. },
  78. '&:disabled': {
  79. color: theme.palette.text03
  80. },
  81. '&.is-mobile': {
  82. ...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
  83. padding: '12px 16px',
  84. paddingRight: '46px'
  85. },
  86. '&.error': {
  87. boxShadow: `0px 0px 0px 2px ${theme.palette.textError}`
  88. }
  89. },
  90. icon: {
  91. position: 'absolute',
  92. top: '8px',
  93. right: '8px',
  94. pointerEvents: 'none',
  95. '&.is-mobile': {
  96. top: '12px',
  97. right: '12px'
  98. }
  99. },
  100. bottomLabel: {
  101. marginTop: theme.spacing(2),
  102. ...withPixelLineHeight(theme.typography.labelRegular),
  103. color: theme.palette.text02,
  104. '&.is-mobile': {
  105. ...withPixelLineHeight(theme.typography.bodyShortRegular)
  106. },
  107. '&.error': {
  108. color: theme.palette.textError
  109. }
  110. }
  111. };
  112. });
  113. const Select = ({
  114. bottomLabel,
  115. className,
  116. disabled,
  117. error,
  118. label,
  119. onChange,
  120. options,
  121. value }: ISelectProps) => {
  122. const { classes, cx, theme } = useStyles();
  123. const isMobile = isMobileBrowser();
  124. return (
  125. <div className = { classes.container }>
  126. {label && <span className = { cx(classes.label, isMobile && 'is-mobile') }>{label}</span>}
  127. <div className = { classes.selectContainer }>
  128. <select
  129. className = { cx(classes.select, isMobile && 'is-mobile', className, error && 'error') }
  130. disabled = { disabled }
  131. onChange = { onChange }
  132. value = { value }>
  133. {options.map(option => (<option
  134. key = { option.value }
  135. value = { option.value }>{option.label}</option>))}
  136. </select>
  137. <Icon
  138. className = { cx(classes.icon, isMobile && 'is-mobile') }
  139. color = { disabled ? theme.palette.icon03 : theme.palette.icon01 }
  140. size = { 22 }
  141. src = { IconArrowDown } />
  142. </div>
  143. {bottomLabel && (
  144. <span className = { cx(classes.bottomLabel, isMobile && 'is-mobile', error && 'error') }>
  145. {bottomLabel}
  146. </span>
  147. )}
  148. </div>
  149. );
  150. };
  151. export default Select;