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.
 
 
 
 

87 regels
2.0 KiB

  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. * Describe of what the component represents.
  37. */
  38. label: PropTypes.string,
  39. }
  40. type Props = PropTypes.InferProps<typeof propTypes>
  41. const Icon: React.FC<Props> = ({
  42. name,
  43. weight = '0.125rem',
  44. size = '1.5rem',
  45. label = name,
  46. }) => {
  47. const iconName = pascalCase(name, { transform: pascalCaseTransformMerge })
  48. const { [iconName as keyof typeof FeatherIcon]: TheIcon = null } = FeatherIcon
  49. const { magnitude: sizeValue, unit: sizeUnit } = splitValueAndUnit(size)
  50. const { magnitude: weightValue } = splitValueAndUnit(weight)
  51. const factor = weightValue * (3 / 2)
  52. if (TheIcon !== null) {
  53. return (
  54. <span>
  55. <StyledIcon
  56. as={TheIcon}
  57. size={undefined}
  58. color={undefined}
  59. strokeLinecap={undefined}
  60. strokeWidth={undefined}
  61. style={{
  62. width: size!,
  63. height: size!,
  64. strokeWidth: `${factor / sizeValue}${sizeUnit}`,
  65. }}
  66. aria-label={label!}
  67. />
  68. <Label aria-hidden="true">{label}</Label>
  69. </span>
  70. )
  71. }
  72. return null
  73. }
  74. Icon.propTypes = propTypes
  75. Icon.displayName = 'Icon'
  76. export default Icon