Design system.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

183 lignes
4.6 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. /**
  50. * Component for performing a navigation action.
  51. */
  52. export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonProps>((
  53. {
  54. variant = 'bare' as const,
  55. subtext,
  56. badge,
  57. menuItem = false,
  58. children,
  59. size = 'medium' as const,
  60. compact = false,
  61. className,
  62. block = false,
  63. component: EnabledComponent = 'a',
  64. disabled = false,
  65. href,
  66. style,
  67. ...etcProps
  68. },
  69. forwardedRef,
  70. ) => {
  71. const Component = disabled ? 'button' : EnabledComponent;
  72. return (
  73. <Component
  74. {...etcProps}
  75. href={disabled ? undefined : href}
  76. type={disabled ? 'button' : undefined}
  77. ref={forwardedRef}
  78. disabled={disabled || undefined}
  79. className={clsx(
  80. 'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none select-none no-underline m-0',
  81. 'focus:outline-0 focus:ring-4',
  82. 'active:ring-tertiary/50',
  83. 'disabled:opacity-50 disabled:cursor-not-allowed',
  84. {
  85. 'flex w-full': block,
  86. 'inline-flex max-w-full align-middle': !block,
  87. },
  88. {
  89. 'pl-2 gap-2': compact,
  90. 'pl-4 gap-4': !compact,
  91. 'pr-4': !(compact || menuItem),
  92. 'pr-2': compact || menuItem,
  93. },
  94. {
  95. 'border-2 border-primary focus:border-secondary active:border-tertiary disabled:border-primary': variant !== 'bare',
  96. 'bg-negative text-primary focus:text-secondary active:text-tertiary disabled:text-primary': variant !== 'filled',
  97. 'bg-primary text-negative focus:bg-secondary active:bg-tertiary focus:text-negative active:text-negative disabled:bg-primary': variant === 'filled',
  98. },
  99. {
  100. 'h-10': size === 'small',
  101. 'h-12': size === 'medium',
  102. 'h-16': size === 'large',
  103. },
  104. className,
  105. )}
  106. data-testid="link"
  107. style={style}
  108. >
  109. <span
  110. className={clsx(
  111. 'flex-auto min-w-0',
  112. {
  113. 'text-left': compact || menuItem,
  114. 'text-center': !(compact || menuItem),
  115. },
  116. )}
  117. >
  118. <span
  119. className="block uppercase font-bold h-[1.1em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded"
  120. data-testid="children"
  121. >
  122. {children}
  123. </span>
  124. {subtext && (
  125. <>
  126. <span className="sr-only">
  127. {' - '}
  128. </span>
  129. <span
  130. className="block h-[1.3em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded font-bold text-xs"
  131. data-testid="subtext"
  132. >
  133. {subtext}
  134. </span>
  135. </>
  136. )}
  137. </span>
  138. {badge && (
  139. <>
  140. <span className="sr-only">
  141. {' - '}
  142. </span>
  143. <span
  144. data-testid="badge"
  145. >
  146. {badge}
  147. </span>
  148. </>
  149. )}
  150. {menuItem && (
  151. <span
  152. data-testid="menuItemIndicator"
  153. >
  154. <svg
  155. className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round"
  156. viewBox="0 0 24 24"
  157. role="presentation"
  158. >
  159. <polyline points="9 18 15 12 9 6" />
  160. </svg>
  161. </span>
  162. )}
  163. </Component>
  164. );
  165. });
  166. LinkButton.displayName = 'LinkButton';
  167. LinkButton.defaultProps = {
  168. variant: 'bare',
  169. size: 'medium',
  170. compact: false,
  171. menuItem: false,
  172. component: 'a',
  173. badge: undefined,
  174. subtext: undefined,
  175. block: false,
  176. disabled: false,
  177. };