interactionStateLayer.tsx 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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. color?: string;
  7. higherOpacity?: boolean;
  8. isHovered?: boolean;
  9. isPressed?: boolean;
  10. }
  11. const InteractionStateLayer = styled(
  12. (props: StateLayerProps) => <span role="presentation" {...props} />,
  13. {shouldForwardProp: p => typeof p === 'string' && isPropValid(p)}
  14. )`
  15. position: absolute;
  16. top: 50%;
  17. left: 50%;
  18. width: 100%;
  19. height: 100%;
  20. transform: translate(-50%, -50%);
  21. box-sizing: content-box;
  22. border-radius: inherit;
  23. border: inherit;
  24. color: ${p => (p.color ? p.theme[p.color] ?? p.color : 'currentcolor')};
  25. background-color: currentcolor;
  26. border-color: currentcolor;
  27. pointer-events: none;
  28. opacity: 0;
  29. ${p =>
  30. defined(p.isHovered)
  31. ? p.isHovered &&
  32. css`
  33. opacity: ${p.higherOpacity ? 0.085 : 0.06};
  34. `
  35. : // If isHovered is undefined, then fallback to a default hover selector
  36. css`
  37. *:hover:not(.focus-visible) > & {
  38. opacity: ${p.higherOpacity ? 0.085 : 0.06};
  39. }
  40. `}
  41. ${p =>
  42. defined(p.isPressed)
  43. ? p.isPressed &&
  44. css`
  45. &&& {
  46. opacity: ${p.higherOpacity ? 0.12 : 0.09};
  47. }
  48. `
  49. : // If isPressed is undefined, then fallback to default press selectors
  50. css`
  51. *:active > &&,
  52. *[aria-expanded='true'] > &&,
  53. *[aria-selected='true'] > && {
  54. opacity: ${p.higherOpacity ? 0.12 : 0.09};
  55. }
  56. `}
  57. *:disabled &&,
  58. *[aria-disabled="true"] && {
  59. opacity: 0;
  60. }
  61. `;
  62. export default InteractionStateLayer;