Design system.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

126 rader
3.3 KiB

  1. import * as React from 'react';
  2. import clsx from 'clsx';
  3. import plugin from 'tailwindcss/plugin';
  4. import { useFallbackId } from '@modal-sh/react-utils';
  5. /**
  6. * Derived HTML element of the {@link RadioTickBox} component.
  7. */
  8. export type RadioTickBoxDerivedElement = HTMLInputElement;
  9. /**
  10. * Props of the {@link RadioTickBox} component.
  11. */
  12. export interface RadioTickBoxProps extends Omit<React.InputHTMLAttributes<RadioTickBoxDerivedElement>, 'type' | 'size'> {
  13. /**
  14. * Should the component occupy the whole width of its parent?
  15. */
  16. block?: boolean;
  17. /**
  18. * Complementary content of the component.
  19. */
  20. subtext?: React.ReactNode;
  21. }
  22. export const radioTickBoxPlugin = plugin(({ addComponents }) => {
  23. addComponents({
  24. '.radio-tick-box': {
  25. '& + label + label > :first-child > :first-child': {
  26. 'display': 'none',
  27. },
  28. '&:checked + label + label > :first-child > :first-child': {
  29. 'display': 'block',
  30. },
  31. },
  32. });
  33. });
  34. /**
  35. * Component for selecting a single value from an array of choices grouped by name.
  36. *
  37. * This component is displayed as a tick box, i.e. a typical radio button.
  38. */
  39. export const RadioTickBox = React.forwardRef<RadioTickBoxDerivedElement, RadioTickBoxProps>((
  40. {
  41. children,
  42. block = false as const,
  43. id: idProp,
  44. className,
  45. subtext,
  46. style,
  47. ...etcProps
  48. },
  49. forwardedRef,
  50. ) => {
  51. const id = useFallbackId(idProp);
  52. return (
  53. <div
  54. className={clsx(
  55. 'gap-x-4 flex-wrap',
  56. block && 'flex',
  57. !block && 'inline-flex align-center',
  58. className,
  59. )}
  60. style={style}
  61. data-testid="base"
  62. >
  63. <input
  64. {...etcProps}
  65. ref={forwardedRef}
  66. type="radio"
  67. id={id}
  68. className="sr-only peer/radio radio-tick-box"
  69. />
  70. <label
  71. htmlFor={id}
  72. className="peer/children order-2 cursor-pointer peer-disabled/radio:cursor-not-allowed"
  73. >
  74. <span
  75. data-testid="children"
  76. >
  77. {children}
  78. </span>
  79. </label>
  80. <label
  81. htmlFor={id}
  82. className={clsx(
  83. 'order-1 block rounded-full ring-secondary/50 overflow-hidden gap-4 leading-none select-none cursor-pointer',
  84. 'peer-focus/radio:outline-0 peer-focus/radio:ring-4 peer-focus/radio:ring-secondary/50',
  85. 'active:ring-tertiary/50 active:ring-4',
  86. 'peer-active/children:ring-tertiary/50 peer-active/children:ring-4 peer-active/children:text-tertiary',
  87. 'peer-disabled/radio:opacity-50 peer-disabled/radio:cursor-not-allowed peer-disabled/radio:ring-0',
  88. 'text-primary peer-disabled/radio:text-primary peer-focus/radio:text-secondary peer-checked/radio:text-tertiary active:text-tertiary',
  89. )}
  90. >
  91. <span
  92. className={clsx(
  93. 'w-6 h-6 block rounded-full border-2 p-0.5 box-border border-current',
  94. )}
  95. >
  96. <span
  97. className={clsx(
  98. 'w-full h-full rounded-full bg-current text-current',
  99. )}
  100. />
  101. </span>
  102. </label>
  103. {subtext && (
  104. <div
  105. className="block w-full text-xs pl-10 order-3"
  106. data-testid="subtext"
  107. >
  108. {subtext}
  109. </div>
  110. )}
  111. </div>
  112. );
  113. });
  114. RadioTickBox.displayName = 'RadioTickBox' as const;
  115. RadioTickBox.defaultProps = {
  116. block: false as const,
  117. subtext: undefined,
  118. };