Design system.
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

194 linhas
4.9 KiB

  1. import * as React from 'react';
  2. import clsx from 'clsx';
  3. import { Button } from '@tesseract-design/web-base';
  4. /**
  5. * Derived HTML element of the {@link LinkButton} component.
  6. */
  7. export type LinkButtonDerivedElement = HTMLAnchorElement;
  8. /**
  9. * Props of the {@link LinkButton} component.
  10. */
  11. export interface LinkButtonProps<T = any> extends Omit<React.HTMLProps<LinkButtonDerivedElement>, 'size'> {
  12. /**
  13. * Should the component occupy the whole width of its parent?
  14. */
  15. block?: boolean;
  16. /**
  17. * Variant of the component.
  18. */
  19. variant?: Button.Variant;
  20. /**
  21. * Complementary content of the component.
  22. */
  23. subtext?: React.ReactNode;
  24. /**
  25. * Short complementary content displayed at the edge of the component.
  26. */
  27. badge?: React.ReactNode;
  28. /**
  29. * Is this component part of a menu?
  30. */
  31. menuItem?: boolean;
  32. /**
  33. * Size of the component.
  34. */
  35. size?: Button.Size;
  36. /**
  37. * Should the component's content use minimal space?
  38. */
  39. compact?: boolean;
  40. /**
  41. * Component to use in rendering.
  42. */
  43. component?: React.ElementType<T>;
  44. /**
  45. * Is the component unable to receive activation?
  46. */
  47. disabled?: boolean;
  48. /**
  49. * Should the children's height be variable?
  50. */
  51. variableChildrenHeight?: boolean;
  52. }
  53. /**
  54. * Component for performing a navigation action.
  55. */
  56. export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonProps>((
  57. {
  58. variant = 'bare' as const,
  59. subtext,
  60. badge,
  61. menuItem = false,
  62. children,
  63. size = 'medium' as const,
  64. compact = false,
  65. className,
  66. block = false,
  67. component: EnabledComponent = 'a',
  68. disabled = false,
  69. href,
  70. style,
  71. variableChildrenHeight = false as const,
  72. ...etcProps
  73. },
  74. forwardedRef,
  75. ) => {
  76. const Component = disabled ? 'button' : EnabledComponent;
  77. return (
  78. <Component
  79. {...etcProps}
  80. href={disabled ? undefined : href}
  81. type={disabled ? 'button' : undefined}
  82. ref={forwardedRef}
  83. disabled={disabled || undefined}
  84. className={clsx(
  85. 'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none select-none no-underline m-0',
  86. 'focus:outline-0 focus:ring-4',
  87. 'active:ring-tertiary/50',
  88. 'disabled:opacity-50 disabled:cursor-not-allowed',
  89. {
  90. 'flex w-full': block,
  91. 'inline-flex max-w-full align-middle': !block,
  92. },
  93. {
  94. 'pl-2 gap-2': compact,
  95. 'pl-4 gap-4': !compact,
  96. 'pr-4': !(compact || menuItem),
  97. 'pr-2': compact || menuItem,
  98. },
  99. {
  100. 'border-2 border-primary focus:border-secondary active:border-tertiary disabled:border-primary': variant !== 'bare',
  101. 'bg-negative text-primary focus:text-secondary active:text-tertiary disabled:text-primary': variant !== 'filled',
  102. 'bg-primary text-negative focus:bg-secondary active:bg-tertiary focus:text-negative active:text-negative disabled:bg-primary': variant === 'filled',
  103. },
  104. {
  105. 'h-10': size === 'small',
  106. 'h-12': size === 'medium',
  107. 'h-16': size === 'large',
  108. },
  109. className,
  110. )}
  111. data-testid="link"
  112. style={style}
  113. >
  114. <span
  115. className={clsx(
  116. 'flex-auto min-w-0',
  117. {
  118. 'text-left': compact || menuItem,
  119. 'text-center': !(compact || menuItem),
  120. },
  121. )}
  122. >
  123. <span
  124. className={clsx(
  125. 'block uppercase font-bold h-[1.1em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded',
  126. {
  127. 'h-[1.1em]': !variableChildrenHeight,
  128. },
  129. )}
  130. data-testid="children"
  131. >
  132. {children}
  133. </span>
  134. {subtext && (
  135. <>
  136. <span className="sr-only">
  137. {' - '}
  138. </span>
  139. <span
  140. className="block h-[1.3em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded font-bold text-xs"
  141. data-testid="subtext"
  142. >
  143. {subtext}
  144. </span>
  145. </>
  146. )}
  147. </span>
  148. {badge && (
  149. <>
  150. <span className="sr-only">
  151. {' - '}
  152. </span>
  153. <span
  154. data-testid="badge"
  155. >
  156. {badge}
  157. </span>
  158. </>
  159. )}
  160. {menuItem && (
  161. <span
  162. data-testid="menuItemIndicator"
  163. >
  164. <svg
  165. className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round"
  166. viewBox="0 0 24 24"
  167. role="presentation"
  168. >
  169. <polyline points="9 18 15 12 9 6" />
  170. </svg>
  171. </span>
  172. )}
  173. </Component>
  174. );
  175. });
  176. LinkButton.displayName = 'LinkButton';
  177. LinkButton.defaultProps = {
  178. variant: 'bare',
  179. size: 'medium',
  180. compact: false,
  181. menuItem: false,
  182. component: 'a',
  183. badge: undefined,
  184. subtext: undefined,
  185. block: false,
  186. disabled: false,
  187. variableChildrenHeight: false as const,
  188. };