Design system.
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.
 
 
 

186 lines
5.0 KiB

  1. import * as React from 'react';
  2. import * as ButtonBase from '@tesseract-design/web-base-button';
  3. import * as CheckControlBase from '@tesseract-design/web-base-checkcontrol';
  4. export type ToggleButtonProps = Omit<React.HTMLProps<HTMLInputElement>, 'size' | 'type' | 'style'> & {
  5. /**
  6. * Size of the component.
  7. */
  8. size?: ButtonBase.ButtonSize,
  9. /**
  10. * Variant of the component.
  11. */
  12. variant?: ButtonBase.ButtonVariant,
  13. /**
  14. * Should the component display a border?
  15. */
  16. border?: boolean,
  17. /**
  18. * Should the component occupy the whole width of its parent?
  19. */
  20. block?: boolean,
  21. /**
  22. * Does the component need to conserve space?
  23. */
  24. compact?: boolean,
  25. /**
  26. * Complementary content of the component.
  27. */
  28. subtext?: React.ReactNode,
  29. /**
  30. * Short complementary content displayed at the edge of the component.
  31. */
  32. badge?: React.ReactNode,
  33. /**
  34. * Does the component have indeterminate check state?
  35. */
  36. indeterminate?: boolean,
  37. }
  38. /**
  39. * Component for performing an action upon activation (e.g. when clicked).
  40. *
  41. * This component functions as a regular button.
  42. */
  43. export const ToggleButton = React.forwardRef<HTMLInputElement, ToggleButtonProps>(
  44. (
  45. {
  46. size = ButtonBase.ButtonSize.MEDIUM,
  47. variant = ButtonBase.ButtonVariant.OUTLINE,
  48. border = false,
  49. children,
  50. block = false,
  51. disabled = false,
  52. compact = false,
  53. subtext,
  54. badge,
  55. indeterminate = false,
  56. className: _className,
  57. as: _as,
  58. ...etcProps
  59. }: ToggleButtonProps,
  60. ref,
  61. ) => {
  62. const styleProps = React.useMemo<ButtonBase.ButtonBaseArgs & CheckControlBase.CheckControlBaseArgs>(() => ({
  63. size,
  64. block,
  65. variant,
  66. border,
  67. compact,
  68. menuItem: false,
  69. disabled,
  70. appearance: CheckControlBase.CheckControlAppearance.BUTTON,
  71. type: CheckControlBase.CheckControlType.CHECKBOX,
  72. uncheckedLabel: false,
  73. }), [size, block, variant, border, compact, disabled]);
  74. const defaultRef = React.useRef<HTMLInputElement>(null);
  75. const theRef = (ref ?? defaultRef) as React.MutableRefObject<HTMLInputElement>;
  76. React.useEffect(() => {
  77. if (!(indeterminate && theRef.current)) {
  78. return;
  79. }
  80. theRef.current.indeterminate = indeterminate;
  81. }, [theRef, indeterminate]);
  82. return (
  83. <div
  84. className={CheckControlBase.ClickAreaWrapper(styleProps)}
  85. >
  86. <label
  87. className={CheckControlBase.ClickArea()}
  88. >
  89. <input
  90. {...etcProps}
  91. disabled={disabled}
  92. type="checkbox"
  93. ref={theRef}
  94. className={CheckControlBase.CheckStateContainer(styleProps)}
  95. />
  96. <span
  97. className={ButtonBase.Button(styleProps)}
  98. >
  99. <span
  100. className={ButtonBase.Border(styleProps)}
  101. />
  102. <span
  103. className={CheckControlBase.CheckIndicatorArea(styleProps)}
  104. >
  105. <span
  106. className={CheckControlBase.CheckIndicatorWrapper(styleProps)}
  107. >
  108. <svg
  109. className={CheckControlBase.CheckIndicator(styleProps)}
  110. viewBox="0 0 24 24"
  111. role="presentation"
  112. >
  113. <polyline
  114. points="20 6 9 17 4 12"
  115. />
  116. </svg>
  117. <svg
  118. className={CheckControlBase.CheckIndicator(styleProps)}
  119. viewBox="0 0 24 24"
  120. role="presentation"
  121. >
  122. <polyline
  123. points="20 12 4 12"
  124. />
  125. </svg>
  126. </span>
  127. </span>
  128. <span
  129. className={ButtonBase.Label(styleProps)}
  130. >
  131. <span
  132. className={ButtonBase.MainText()}
  133. data-testid="children"
  134. >
  135. <span
  136. className={ButtonBase.OverflowText()}
  137. >
  138. {children}
  139. </span>
  140. </span>
  141. {
  142. subtext
  143. && (
  144. <>
  145. {' '}
  146. <span
  147. className={ButtonBase.Subtext()}
  148. data-testid="subtext"
  149. >
  150. <span
  151. className={ButtonBase.OverflowText()}
  152. >
  153. {subtext}
  154. </span>
  155. </span>
  156. </>
  157. )
  158. }
  159. </span>
  160. {
  161. badge
  162. && (
  163. <>
  164. {' '}
  165. <span
  166. className={ButtonBase.BadgeContainer(styleProps)}
  167. data-testid="badge"
  168. >
  169. {badge}
  170. </span>
  171. </>
  172. )
  173. }
  174. </span>
  175. </label>
  176. </div>
  177. );
  178. },
  179. );
  180. ToggleButton.displayName = 'ActionButton';