VizRepeater.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import React, { PureComponent } from 'react';
  2. import { VizOrientation } from '../../types';
  3. interface Props<T> {
  4. renderValue: (value: T, width: number, height: number) => JSX.Element;
  5. height: number;
  6. width: number;
  7. source: any; // If this changes, new values will be requested
  8. getValues: () => T[];
  9. renderCounter: number; // force update of values & render
  10. orientation: VizOrientation;
  11. itemSpacing?: number;
  12. }
  13. interface DefaultProps {
  14. itemSpacing: number;
  15. }
  16. type PropsWithDefaults<T> = Props<T> & DefaultProps;
  17. interface State<T> {
  18. values: T[];
  19. }
  20. export class VizRepeater<T> extends PureComponent<Props<T>, State<T>> {
  21. static defaultProps: DefaultProps = {
  22. itemSpacing: 10,
  23. };
  24. constructor(props: Props<T>) {
  25. super(props);
  26. this.state = {
  27. values: props.getValues(),
  28. };
  29. }
  30. componentDidUpdate(prevProps: Props<T>) {
  31. const { renderCounter, source } = this.props;
  32. if (renderCounter !== prevProps.renderCounter || source !== prevProps.source) {
  33. this.setState({ values: this.props.getValues() });
  34. }
  35. }
  36. getOrientation(): VizOrientation {
  37. const { orientation, width, height } = this.props;
  38. if (orientation === VizOrientation.Auto) {
  39. if (width > height) {
  40. return VizOrientation.Vertical;
  41. } else {
  42. return VizOrientation.Horizontal;
  43. }
  44. }
  45. return orientation;
  46. }
  47. render() {
  48. const { renderValue, height, width, itemSpacing } = this.props as PropsWithDefaults<T>;
  49. const { values } = this.state;
  50. const orientation = this.getOrientation();
  51. const itemStyles: React.CSSProperties = {
  52. display: 'flex',
  53. };
  54. const repeaterStyle: React.CSSProperties = {
  55. display: 'flex',
  56. };
  57. let vizHeight = height;
  58. let vizWidth = width;
  59. if (orientation === VizOrientation.Horizontal) {
  60. repeaterStyle.flexDirection = 'column';
  61. itemStyles.margin = `${itemSpacing / 2}px 0`;
  62. vizWidth = width;
  63. vizHeight = height / values.length - itemSpacing;
  64. } else {
  65. repeaterStyle.flexDirection = 'row';
  66. itemStyles.margin = `0 ${itemSpacing / 2}px`;
  67. vizHeight = height;
  68. vizWidth = width / values.length - itemSpacing;
  69. }
  70. itemStyles.width = `${vizWidth}px`;
  71. itemStyles.height = `${vizHeight}px`;
  72. return (
  73. <div style={repeaterStyle}>
  74. {values.map((value, index) => {
  75. return (
  76. <div key={index} style={itemStyles}>
  77. {renderValue(value, vizWidth, vizHeight)}
  78. </div>
  79. );
  80. })}
  81. </div>
  82. );
  83. }
  84. }