matrix.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import {type ElementType} from 'react';
  2. import styled from '@emotion/styled';
  3. import first from 'lodash/first';
  4. import JSXProperty from 'sentry/components/stories/jsxProperty';
  5. import SizingWindow, {
  6. Props as SizingWindowProps,
  7. } from 'sentry/components/stories/sizingWindow';
  8. import {space} from 'sentry/styles/space';
  9. type RenderProps = {};
  10. export type PropMatrix<P extends RenderProps> = Partial<{
  11. [Prop in keyof P]: P[Prop][];
  12. }>;
  13. interface Props<P extends RenderProps> {
  14. propMatrix: PropMatrix<P>;
  15. render: ElementType<P>;
  16. selectedProps: [keyof P, keyof P];
  17. sizingWindowProps?: SizingWindowProps;
  18. }
  19. export default function Matrix<P extends RenderProps>({
  20. propMatrix,
  21. render,
  22. selectedProps,
  23. sizingWindowProps,
  24. }: Props<P>) {
  25. const defaultValues = Object.fromEntries(
  26. Object.entries(propMatrix).map(([key, values]) => {
  27. return [key, first(values as any)];
  28. })
  29. );
  30. const values1 = propMatrix[selectedProps[0]] ?? [];
  31. const values2 = propMatrix[selectedProps[1]] ?? [];
  32. const items = values1.flatMap(value1 => {
  33. const label = (
  34. <div>
  35. <JSXProperty name={String(selectedProps[0])} value={value1} />
  36. </div>
  37. );
  38. const content = values2.map(value2 => {
  39. return item(
  40. render,
  41. {
  42. ...defaultValues,
  43. [selectedProps[0]]: value1,
  44. [selectedProps[1]]: value2,
  45. },
  46. sizingWindowProps
  47. );
  48. });
  49. return [label, ...content];
  50. });
  51. return (
  52. <div>
  53. <h4 style={{margin: 0}}>
  54. <samp>{selectedProps[0]}</samp> vs <samp>{selectedProps[1]}</samp>
  55. </h4>
  56. <Grid
  57. style={{
  58. gridTemplateColumns: `max-content repeat(${values2.length}, max-content)`,
  59. }}
  60. >
  61. <div key="space-head" />
  62. {values2.map(value2 => (
  63. <div key={`title-2-${value2}`}>
  64. <JSXProperty name={String(selectedProps[1])} value={value2} />
  65. </div>
  66. ))}
  67. {items}
  68. </Grid>
  69. </div>
  70. );
  71. }
  72. function item(Component, props, sizingWindowProps) {
  73. const hasChildren = 'children' in props;
  74. return hasChildren ? (
  75. <SizingWindow key={JSON.stringify(props)} {...sizingWindowProps}>
  76. <Component {...props}>{props.children}</Component>
  77. </SizingWindow>
  78. ) : (
  79. <SizingWindow key={JSON.stringify(props)} {...sizingWindowProps}>
  80. <Component {...props} />
  81. </SizingWindow>
  82. );
  83. }
  84. const Grid = styled('section')`
  85. display: grid;
  86. gap: ${space(1)};
  87. align-items: center;
  88. padding: var(--stories-grid-space);
  89. `;