Common front-end components for Web using the Tesseract design system, written for React. https://make.modal.sh/tesseract/web/react/common
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

99 行
2.3 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. * 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. const Icon: React.FC<Props> = ({
  50. name,
  51. weight = '0.125rem',
  52. size = '1.5rem',
  53. style = {},
  54. label = name,
  55. className = '',
  56. ...etcProps
  57. }) => {
  58. const iconName = pascalCase(name, { transform: pascalCaseTransformMerge })
  59. const { [iconName as keyof typeof FeatherIcon]: TheIcon = null } = FeatherIcon
  60. const { magnitude: sizeValue, unit: sizeUnit } = splitValueAndUnit(size)
  61. const { magnitude: weightValue } = splitValueAndUnit(weight)
  62. const factor = weightValue * (3 / 2)
  63. if (TheIcon !== null) {
  64. return (
  65. <span {...etcProps} style={style!}>
  66. <StyledIcon
  67. className={className!}
  68. as={TheIcon}
  69. size={undefined}
  70. color={undefined}
  71. strokeLinecap={undefined}
  72. strokeWidth={undefined}
  73. style={{
  74. width: size!,
  75. height: size!,
  76. strokeWidth: `${factor / sizeValue}${sizeUnit}`,
  77. }}
  78. aria-label={label!}
  79. />
  80. <Label aria-hidden="true">{label}</Label>
  81. </span>
  82. )
  83. }
  84. return null
  85. }
  86. Icon.propTypes = propTypes
  87. Icon.displayName = 'Icon'
  88. export default Icon