interactionStateLayer.tsx 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import isPropValid from '@emotion/is-prop-valid';
  2. import {css} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import {defined} from 'sentry/utils';
  5. interface StateLayerProps extends React.HTMLAttributes<HTMLSpanElement> {
  6. as?: React.ElementType;
  7. color?: string;
  8. higherOpacity?: boolean;
  9. isHovered?: boolean;
  10. isPressed?: boolean;
  11. }
  12. const InteractionStateLayer = styled(
  13. (props: StateLayerProps) => {
  14. const {children, as: Element = 'span', ...rest} = props;
  15. // Here, using `as` directly doesn't work because it loses the `role` prop. Instead, manually propagating the props does the right thing.
  16. return (
  17. <Element {...rest} role="presentation">
  18. {children}
  19. </Element>
  20. );
  21. },
  22. {shouldForwardProp: p => isPropValid(p) || p === 'as'}
  23. )`
  24. position: absolute;
  25. top: 50%;
  26. left: 50%;
  27. width: 100%;
  28. height: 100%;
  29. transform: translate(-50%, -50%);
  30. box-sizing: content-box;
  31. border-radius: inherit;
  32. border: inherit;
  33. color: ${p => (p.color ? p.theme[p.color] ?? p.color : 'currentcolor')};
  34. background-color: currentcolor;
  35. border-color: currentcolor;
  36. pointer-events: none;
  37. opacity: 0;
  38. ${p =>
  39. defined(p.isHovered)
  40. ? p.isHovered &&
  41. css`
  42. opacity: ${p.higherOpacity ? 0.085 : 0.06};
  43. `
  44. : // If isHovered is undefined, then fallback to a default hover selector
  45. css`
  46. *:hover:not(:focus-visible) > & {
  47. opacity: ${p.higherOpacity ? 0.085 : 0.06};
  48. }
  49. `}
  50. ${p =>
  51. defined(p.isPressed)
  52. ? p.isPressed &&
  53. css`
  54. &&& {
  55. opacity: ${p.higherOpacity ? 0.12 : 0.09};
  56. }
  57. `
  58. : // If isPressed is undefined, then fallback to default press selectors
  59. css`
  60. *:active > &&,
  61. *[aria-expanded='true'] > &&,
  62. *[aria-selected='true'] > && {
  63. opacity: ${p.higherOpacity ? 0.12 : 0.09};
  64. }
  65. `}
  66. *:disabled &&,
  67. *[aria-disabled="true"] && {
  68. opacity: 0;
  69. }
  70. `;
  71. export default InteractionStateLayer;