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

Icon.tsx 3.0 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import * as React from 'react'
  2. import * as PropTypes from 'prop-types'
  3. import * as FeatherIcon from 'react-feather'
  4. import styled from 'styled-components'
  5. import { pascalCase, pascalCaseTransformMerge } from 'pascal-case'
  6. import splitValueAndUnit from '../../services/splitValueAndUnit'
  7. const Label = styled('span')({
  8. 'position': 'absolute',
  9. 'left': -999999,
  10. 'width': 1,
  11. 'height': 1,
  12. ':empty': {
  13. display: 'none',
  14. },
  15. })
  16. const StyledIcon = styled('svg')({
  17. stroke: 'currentColor',
  18. strokeLinecap: 'round',
  19. display: 'inline-block',
  20. verticalAlign: 'middle',
  21. })
  22. const propTypes = {
  23. /**
  24. * Name of the icon to display.
  25. */
  26. name: PropTypes.string.isRequired,
  27. /**
  28. * Width of the icon's strokes.
  29. */
  30. weight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  31. /**
  32. * Size of the icon. This controls both the width and the height.
  33. */
  34. size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  35. /**
  36. * CSS style of the icon. For icon dimensions, use `size` instead.
  37. */
  38. style: PropTypes.object,
  39. /**
  40. * Describe of what the component represents.
  41. */
  42. label: PropTypes.string,
  43. /**
  44. * Class name used for styling.
  45. */
  46. className: PropTypes.string,
  47. }
  48. type Props = PropTypes.InferProps<typeof propTypes>
  49. /**
  50. * Component for displaying graphical icons.
  51. *
  52. * @see {@link //feathericons.com|Feather Icons} for a complete list of icons.
  53. * @param {string} name - Name of the icon to display.
  54. * @param {string} weight - Width of the icon's strokes.
  55. * @param {string | number} [size] - Size of the icon. This controls both the width and the height.
  56. * @param {CSSProperties} [style] - CSS style of the icon. For icon dimensions, use `size` instead.
  57. * @param {string} [label] - Describe of what the component represents.
  58. * @param {string} [className] - Class name used for styling.
  59. * @param {object} etcProps - The rest of the props.
  60. * @returns {React.ReactElement | null} - The component elements.
  61. */
  62. const Icon: React.FC<Props> = ({
  63. name,
  64. weight = '0.125rem',
  65. size = '1.5rem',
  66. style = {},
  67. label = name,
  68. className = '',
  69. ...etcProps
  70. }) => {
  71. const iconName = pascalCase(name, { transform: pascalCaseTransformMerge })
  72. const { [iconName as keyof typeof FeatherIcon]: TheIcon = null } = FeatherIcon
  73. const { magnitude: sizeValue, unit: sizeUnit } = splitValueAndUnit(size)
  74. const { magnitude: weightValue } = splitValueAndUnit(weight)
  75. const factor = weightValue * (3 / 2)
  76. if (TheIcon !== null) {
  77. return (
  78. <span {...etcProps} style={style!}>
  79. <StyledIcon
  80. className={className!}
  81. as={TheIcon}
  82. size={undefined}
  83. color={undefined}
  84. strokeLinecap={undefined}
  85. strokeWidth={undefined}
  86. style={{
  87. width: size!,
  88. height: size!,
  89. strokeWidth: `${factor / sizeValue}${sizeUnit}`,
  90. }}
  91. aria-label={label!}
  92. />
  93. <Label aria-hidden="true">{label}</Label>
  94. </span>
  95. )
  96. }
  97. return null
  98. }
  99. Icon.propTypes = propTypes
  100. Icon.displayName = 'Icon'
  101. export default Icon