You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RadioButton.tsx 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import styled from '@emotion/styled';
  21. import classNames from 'classnames';
  22. import React from 'react';
  23. import tw from 'twin.macro';
  24. import { themeBorder, themeColor } from '../helpers/theme';
  25. type AllowedRadioButtonAttributes = Pick<
  26. React.InputHTMLAttributes<HTMLInputElement>,
  27. 'aria-label' | 'autoFocus' | 'id' | 'name' | 'style' | 'title' | 'type'
  28. >;
  29. interface Props extends AllowedRadioButtonAttributes {
  30. checked: boolean;
  31. children?: React.ReactNode;
  32. className?: string;
  33. disabled?: boolean;
  34. onCheck: (value: string) => void;
  35. value: string;
  36. }
  37. export default function RadioButton({
  38. checked,
  39. children,
  40. className,
  41. disabled,
  42. onCheck,
  43. value,
  44. ...htmlProps
  45. }: Props) {
  46. const handleChange = () => {
  47. if (!disabled) {
  48. onCheck(value);
  49. }
  50. };
  51. return (
  52. <label className={classNames('sw-flex sw-items-center', className)}>
  53. <RadioButtonStyled
  54. aria-disabled={disabled}
  55. checked={checked}
  56. disabled={disabled}
  57. onChange={handleChange}
  58. type="radio"
  59. value={value}
  60. {...htmlProps}
  61. />
  62. {children}
  63. </label>
  64. );
  65. }
  66. export const RadioButtonStyled = styled.input`
  67. appearance: none; //disables native style
  68. border: ${themeBorder('default', 'radioBorder')};
  69. ${tw`sw-w-4 sw-min-w-4 sw-h-4 sw-min-h-4`}
  70. ${tw`sw-p-1 sw-mr-2`}
  71. ${tw`sw-inline-block`}
  72. ${tw`sw-box-border`}
  73. ${tw`sw-rounded-pill`}
  74. &:hover {
  75. background: ${themeColor('radioHover')};
  76. }
  77. &:focus,
  78. &:focus-visible {
  79. background: ${themeColor('radioHover')};
  80. border: ${themeBorder('default', 'radioFocusBorder')};
  81. outline: ${themeBorder('focus', 'radioFocusOutline')};
  82. }
  83. &:focus:checked,
  84. &:focus-visible:checked,
  85. &:hover:checked,
  86. &:checked {
  87. // Color cannot be used with multiple backgrounds, only image is allowed
  88. background-image: linear-gradient(to right, ${themeColor('radio')}, ${themeColor('radio')}),
  89. linear-gradient(to right, ${themeColor('radioChecked')}, ${themeColor('radioChecked')});
  90. background-clip: content-box, padding-box;
  91. border: ${themeBorder('default', 'radioBorder')};
  92. }
  93. &:disabled {
  94. background: ${themeColor('radioDisabledBackground')};
  95. border: ${themeBorder('default', 'radioDisabledBorder')};
  96. background-clip: unset;
  97. ${tw`sw-cursor-not-allowed`}
  98. &:checked {
  99. background-image: linear-gradient(
  100. to right,
  101. ${themeColor('radioDisabled')},
  102. ${themeColor('radioDisabled')}
  103. ),
  104. linear-gradient(
  105. to right,
  106. ${themeColor('radioDisabledBackground')},
  107. ${themeColor('radioDisabledBackground')}
  108. );
  109. background-clip: content-box, padding-box;
  110. border: ${themeBorder('default', 'radioDisabledBorder')};
  111. }
  112. }
  113. `;