placeholder.tsx 1.2 KB

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