Common front-end components for Web using the Tesseract design system, written for React. https://make.modal.sh/tesseract/web/react/common
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.

Button.tsx 3.4 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import * as React from 'react'
  2. import * as PropTypes from 'prop-types'
  3. import styled from 'styled-components'
  4. import { Size, SizeMap } from '../../services/utilities'
  5. import stringify from '../../services/stringify'
  6. export type Variant = 'outline' | 'primary'
  7. const MIN_HEIGHTS: SizeMap<string | number> = {
  8. small: '2.5rem',
  9. medium: '3rem',
  10. large: '4rem',
  11. }
  12. const Base = styled('button')({
  13. 'appearance': 'none',
  14. 'padding': '0 1rem',
  15. 'font': 'inherit',
  16. 'fontFamily': 'var(--font-family-base)',
  17. 'textTransform': 'uppercase',
  18. 'fontWeight': 'bolder',
  19. 'borderRadius': '0.25rem',
  20. 'placeContent': 'center',
  21. 'position': 'relative',
  22. 'cursor': 'pointer',
  23. 'border': 0,
  24. 'userSelect': 'none',
  25. 'textDecoration': 'none',
  26. 'transitionProperty': 'background-color, color',
  27. 'whiteSpace': 'nowrap',
  28. 'lineHeight': 1,
  29. ':focus': {
  30. '--color-accent': 'var(--color-active, Highlight)',
  31. 'outline': 0,
  32. },
  33. ':disabled': {
  34. opacity: 0.5,
  35. cursor: 'not-allowed',
  36. },
  37. '::-moz-focus-inner': {
  38. outline: 0,
  39. border: 0,
  40. },
  41. })
  42. Base.displayName = 'button'
  43. const Border = styled('span')({
  44. 'borderColor': 'var(--color-accent, blue)',
  45. 'boxSizing': 'border-box',
  46. 'display': 'inline-block',
  47. 'borderWidth': '0.125rem',
  48. 'borderStyle': 'solid',
  49. 'position': 'absolute',
  50. 'top': 0,
  51. 'left': 0,
  52. 'width': '100%',
  53. 'height': '100%',
  54. 'borderRadius': 'inherit',
  55. 'pointerEvents': 'none',
  56. 'transitionProperty': 'border-color',
  57. '::before': {
  58. position: 'absolute',
  59. top: 0,
  60. left: 0,
  61. width: '100%',
  62. height: '100%',
  63. content: "''",
  64. borderRadius: '0.125rem',
  65. opacity: 0.5,
  66. pointerEvents: 'none',
  67. },
  68. [`${Base}:focus &::before`]: {
  69. boxShadow: '0 0 0 0.375rem var(--color-accent, blue)',
  70. },
  71. })
  72. Border.displayName = 'span'
  73. const propTypes = {
  74. /**
  75. * Size of the component.
  76. */
  77. size: PropTypes.oneOf<Size>(['small', 'medium', 'large']),
  78. /**
  79. * Variant of the component.
  80. */
  81. variant: PropTypes.oneOf<Exclude<Variant, 'unknown'>>(['outline', 'primary']),
  82. /**
  83. * Should the component take up the remaining space parallel to the content flow?
  84. */
  85. block: PropTypes.bool,
  86. /**
  87. * Text to identify the action associated upon activation of the component.
  88. */
  89. children: PropTypes.any,
  90. /**
  91. * Can the component be activated?
  92. */
  93. disabled: PropTypes.bool,
  94. }
  95. type Props = PropTypes.InferProps<typeof propTypes>
  96. const defaultVariantStyleSet: React.CSSProperties = {
  97. backgroundColor: 'transparent',
  98. color: 'var(--color-accent, blue)',
  99. }
  100. const variantStyleSets: Record<Variant, React.CSSProperties> = {
  101. outline: defaultVariantStyleSet,
  102. primary: {
  103. backgroundColor: 'var(--color-accent, blue)',
  104. color: 'var(--color-bg, white)',
  105. },
  106. }
  107. const Button = React.forwardRef<HTMLButtonElement, Props>(
  108. ({ size = 'medium', variant = 'outline', block = false, disabled = false, children, ...etcProps }, ref) => {
  109. const { [variant as Variant]: theVariantStyleSet = defaultVariantStyleSet } = variantStyleSets
  110. return (
  111. <Base
  112. {...etcProps}
  113. ref={ref}
  114. disabled={disabled!}
  115. style={{
  116. ...theVariantStyleSet,
  117. minHeight: MIN_HEIGHTS[size as Size],
  118. width: block ? '100%' : undefined,
  119. display: block ? 'grid' : 'inline-grid',
  120. }}
  121. >
  122. <Border />
  123. {stringify(children)}
  124. </Base>
  125. )
  126. },
  127. )
  128. Button.propTypes = propTypes
  129. Button.displayName = 'Button'
  130. export default Button