multipleCheckbox.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import {useCallback} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Choices} from 'sentry/types';
  4. import {defined} from 'sentry/utils';
  5. const MultipleCheckboxWrapper = styled('div')`
  6. display: flex;
  7. flex-wrap: wrap;
  8. `;
  9. const Label = styled('label')`
  10. font-weight: normal;
  11. white-space: nowrap;
  12. margin-right: 10px;
  13. margin-bottom: 10px;
  14. width: 20%;
  15. `;
  16. const CheckboxLabel = styled('span')`
  17. margin-left: 3px;
  18. `;
  19. type SelectedValue = (string | number)[];
  20. type Props = {
  21. choices: Choices;
  22. value: (string | number)[];
  23. disabled?: boolean;
  24. onChange?: (value: SelectedValue, event: React.ChangeEvent<HTMLInputElement>) => void;
  25. };
  26. function MultipleCheckbox({choices, value, disabled, onChange}: Props) {
  27. const handleChange = useCallback(
  28. (selectedValue: string | number, e: React.ChangeEvent<HTMLInputElement>) => {
  29. let newValue: SelectedValue = [];
  30. if (typeof onChange !== 'function') {
  31. return;
  32. }
  33. if (e.target.checked) {
  34. newValue = value ? [...value, selectedValue] : [value];
  35. } else {
  36. newValue = value.filter(v => v !== selectedValue);
  37. }
  38. onChange(newValue, e);
  39. },
  40. [value, onChange]
  41. );
  42. return (
  43. <MultipleCheckboxWrapper>
  44. {choices.map(([choiceValue, choiceLabel]) => (
  45. <LabelContainer key={choiceValue}>
  46. <Label>
  47. <input
  48. type="checkbox"
  49. value={choiceValue}
  50. onChange={e => handleChange(choiceValue, e)}
  51. disabled={disabled}
  52. checked={defined(value) && value.indexOf(choiceValue) !== -1}
  53. />
  54. <CheckboxLabel>{choiceLabel}</CheckboxLabel>
  55. </Label>
  56. </LabelContainer>
  57. ))}
  58. </MultipleCheckboxWrapper>
  59. );
  60. }
  61. export default MultipleCheckbox;
  62. const LabelContainer = styled('div')`
  63. width: 100%;
  64. @media (min-width: ${p => p.theme.breakpoints.small}) {
  65. width: 50%;
  66. }
  67. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  68. width: 33.333%;
  69. }
  70. @media (min-width: ${p => p.theme.breakpoints.large}) {
  71. width: 25%;
  72. }
  73. `;