1import { css } from '@emotion/react';
2import { theme, typography } from '@expo/styleguide';
3import { PropsWithChildren } from 'react';
4
5const MDX_CLASS_NAME_TO_TAB_NAME: Record<string, string> = {
6  'language-swift': 'Swift',
7  'language-kotlin': 'Kotlin',
8  'language-javascript': 'JavaScript',
9  'language-typescript': 'TypeScript',
10  'language-json': 'JSON',
11  'language-ruby': 'Ruby',
12  'language-groovy': 'Gradle',
13};
14
15const CodeSamplesCSS = css`
16  display: flex;
17  flex-direction: row;
18  max-width: 100%;
19  margin: 20px 0;
20
21  .code-block-column {
22    display: flex;
23    flex-direction: column;
24    flex: 1;
25    margin-right: -1px;
26    min-width: 0;
27
28    pre {
29      border-top-left-radius: 0;
30      border-top-right-radius: 0;
31    }
32    &:not(:first-of-type) pre {
33      border-bottom-left-radius: 0;
34    }
35    &:not(:last-child) pre {
36      border-bottom-right-radius: 0;
37    }
38    &:first-of-type .code-block-header {
39      border-top-left-radius: 4px;
40    }
41    &:last-child .code-block-header {
42      border-top-right-radius: 4px;
43    }
44  }
45  .code-block-header {
46    padding: 6px 16px;
47    background-color: ${theme.background.secondary};
48    border: 1px solid ${theme.border.default};
49    border-bottom-width: 0px;
50
51    span {
52      ${typography.fontSizes[15]}
53      color: ${theme.text.default};
54      font-family: ${typography.fontFaces.mono};
55    }
56  }
57  .code-block-content {
58    flex: 1;
59    overflow-x: auto;
60
61    pre {
62      height: 100%;
63      margin: 0;
64
65      ::-webkit-scrollbar {
66        height: 6px;
67      }
68      ::-webkit-scrollbar-track {
69        background: ${theme.background.secondary};
70      }
71      ::-webkit-scrollbar-thumb {
72        background: ${theme.background.tertiary};
73        border-radius: 10px;
74      }
75      ::-webkit-scrollbar-thumb:hover {
76        background: ${theme.background.quaternary};
77      }
78    }
79  }
80`;
81
82type Props = PropsWithChildren<{
83  tabs?: string[];
84}>;
85
86export function CodeBlocksTable({ children, tabs, ...rest }: Props) {
87  const childrenArray = Array.isArray(children) ? children : [children];
88  const codeBlocks = childrenArray.filter(
89    ({ props }) =>
90      props.children.props.className && props.children.props.className.startsWith('language-')
91  );
92  const tabNames =
93    tabs ||
94    codeBlocks.map(child => {
95      const className = child.props.children.props.className;
96      return MDX_CLASS_NAME_TO_TAB_NAME[className] || className.replace('language-', '');
97    });
98
99  return (
100    <div css={CodeSamplesCSS} {...rest}>
101      {codeBlocks.map((codeBlock, index) => (
102        <div key={index} className="code-block-column">
103          <div className="code-block-header">
104            <span>{tabNames[index]}</span>
105          </div>
106          <div className="code-block-content">{codeBlock}</div>
107        </div>
108      ))}
109    </div>
110  );
111}
112