selectOption.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import {Fragment} from 'react';
  2. import {components as selectComponents} from 'react-select';
  3. import {ClassNames} from '@emotion/react';
  4. import styled from '@emotion/styled';
  5. import MenuListItem from 'sentry/components/menuListItem';
  6. import {IconCheckmark} from 'sentry/icons';
  7. import {defined} from 'sentry/utils';
  8. type Props = React.ComponentProps<typeof selectComponents.Option>;
  9. // We still have some tests that find select options by the display name "Option".
  10. MenuListItem.displayName = 'Option';
  11. function SelectOption(props: Props) {
  12. const {
  13. label,
  14. data,
  15. selectProps,
  16. isMulti,
  17. isSelected,
  18. isFocused,
  19. isDisabled,
  20. innerProps,
  21. innerRef,
  22. } = props;
  23. const {showDividers, size} = selectProps;
  24. const {value, selectionMode, priority, ...itemProps} = data;
  25. const isMultiple = defined(selectionMode) ? selectionMode === 'multiple' : isMulti;
  26. // Unless the priority prop is explicitly defined, use 'primary' for
  27. // selected items in single-selection menus and 'default' for the rest.
  28. const itemPriority = priority ?? (isSelected && !isMultiple ? 'primary' : 'default');
  29. return (
  30. <ClassNames>
  31. {({cx}) => (
  32. <MenuListItem
  33. {...itemProps}
  34. {...innerProps}
  35. ref={innerRef}
  36. className={cx({
  37. option: true,
  38. 'option--is-disabled': isDisabled,
  39. 'option--is-focused': isFocused,
  40. 'option--is-selected': isSelected,
  41. })}
  42. as="div"
  43. value={value}
  44. label={label}
  45. disabled={isDisabled}
  46. isFocused={isFocused}
  47. showDivider={showDividers}
  48. priority={itemPriority}
  49. size={size}
  50. innerWrapProps={{'data-test-id': value}}
  51. labelProps={{as: typeof label === 'string' ? 'p' : 'div'}}
  52. leadingItems={
  53. <Fragment>
  54. <CheckWrap isMultiple={isMultiple} isSelected={isSelected}>
  55. {isSelected && (
  56. <IconCheckmark
  57. size={isMultiple ? 'xs' : 'sm'}
  58. color={isMultiple ? 'white' : undefined}
  59. />
  60. )}
  61. </CheckWrap>
  62. {data.leadingItems}
  63. </Fragment>
  64. }
  65. />
  66. )}
  67. </ClassNames>
  68. );
  69. }
  70. export default SelectOption;
  71. const CheckWrap = styled('div')<{isMultiple: boolean; isSelected: boolean}>`
  72. display: flex;
  73. justify-content: center;
  74. align-items: center;
  75. ${p =>
  76. p.isMultiple
  77. ? `
  78. width: 1em;
  79. height: 1em;
  80. padding: 1px;
  81. border: solid 1px ${p.theme.border};
  82. background: ${p.theme.backgroundElevated};
  83. border-radius: 2px;
  84. box-shadow: inset ${p.theme.dropShadowLight};
  85. ${
  86. p.isSelected &&
  87. `
  88. background: ${p.theme.purple300};
  89. border-color: ${p.theme.purple300};
  90. `
  91. }
  92. `
  93. : `
  94. width: 1em;
  95. height: 1.4em;
  96. padding-bottom: 1px;
  97. `}
  98. `;