placeholder.tsx 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. import styled from '@emotion/styled';
  2. import {space, ValidSize} from 'sentry/styles/space';
  3. export interface PlaceholderProps {
  4. bottomGutter?: ValidSize;
  5. children?: React.ReactNode;
  6. className?: string;
  7. error?: React.ReactNode;
  8. height?: string;
  9. shape?: 'rect' | 'circle';
  10. testId?: string;
  11. width?: string;
  12. }
  13. const defaultProps = {
  14. shape: 'rect',
  15. bottomGutter: 0 as Parameters<typeof space>[0],
  16. width: '100%',
  17. height: '60px',
  18. testId: 'loading-placeholder',
  19. } satisfies Partial<PlaceholderProps>;
  20. const Placeholder = styled(({className, children, error, testId}: PlaceholderProps) => {
  21. return (
  22. <div data-test-id={testId} className={className}>
  23. {error || children}
  24. </div>
  25. );
  26. })<PlaceholderProps>`
  27. display: flex;
  28. flex-direction: column;
  29. flex-shrink: 0;
  30. justify-content: center;
  31. align-items: center;
  32. background-color: ${p => (p.error ? p.theme.red100 : p.theme.backgroundSecondary)};
  33. ${p => p.error && `color: ${p.theme.red200};`}
  34. width: ${p => p.width};
  35. height: ${p => p.height};
  36. ${p => (p.shape === 'circle' ? 'border-radius: 100%;' : '')}
  37. ${p =>
  38. typeof p.bottomGutter === 'number' && p.bottomGutter > 0
  39. ? `margin-bottom: ${space(p.bottomGutter)};`
  40. : ''}
  41. `;
  42. Placeholder.defaultProps = defaultProps;
  43. export default Placeholder;