1import { css } from '@emotion/react';
2import { breakpoints, spacing } from '@expo/styleguide-base';
3import { FileCode01Icon } from '@expo/styleguide-icons';
4import { PropsWithChildren } from 'react';
5
6import { cleanCopyValue } from '~/components/base/code';
7import { Snippet } from '~/ui/components/Snippet/Snippet';
8import { SnippetContent } from '~/ui/components/Snippet/SnippetContent';
9import { SnippetHeader } from '~/ui/components/Snippet/SnippetHeader';
10import { CopyAction } from '~/ui/components/Snippet/actions/CopyAction';
11
12const MDX_CLASS_NAME_TO_TAB_NAME: Record<string, string> = {
13  'language-swift': 'Swift',
14  'language-kotlin': 'Kotlin',
15  'language-javascript': 'JavaScript',
16  'language-typescript': 'TypeScript',
17  'language-json': 'JSON',
18  'language-ruby': 'Ruby',
19  'language-groovy': 'Gradle',
20};
21
22type Props = PropsWithChildren<{
23  tabs?: string[];
24  connected?: boolean;
25}>;
26
27export function CodeBlocksTable({ children, tabs, connected = true, ...rest }: Props) {
28  const childrenArray = Array.isArray(children) ? children : [children];
29  const codeBlocks = childrenArray.filter(
30    ({ props }) =>
31      props.children.props.className && props.children.props.className.startsWith('language-')
32  );
33  const tabNames =
34    tabs ||
35    codeBlocks.map(child => {
36      const className = child.props.children.props.className;
37      return MDX_CLASS_NAME_TO_TAB_NAME[className] || className.replace('language-', '');
38    });
39
40  console.warn(codeBlocks);
41
42  return (
43    <div css={[codeBlocksWrapperStyle, connected && codeBlockConnectedWrapperStyle]} {...rest}>
44      {codeBlocks.map((codeBlock, index) => (
45        <Snippet key={index} css={snippetWrapperStyle}>
46          <SnippetHeader title={tabNames[index]} Icon={FileCode01Icon}>
47            <CopyAction text={cleanCopyValue(codeBlock.props.children.props.children)} />
48          </SnippetHeader>
49          <SnippetContent className="p-0 h-full">{codeBlock}</SnippetContent>
50        </Snippet>
51      ))}
52    </div>
53  );
54}
55
56const codeBlocksWrapperStyle = css({
57  display: 'grid',
58  gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)',
59  gap: spacing[4],
60  gridAutoRows: '1fr',
61
62  pre: {
63    border: 0,
64    margin: 0,
65    gridTemplateRows: 'minmax(100px, 1fr)',
66    height: '100%',
67  },
68
69  [`@media screen and (max-width: ${breakpoints.large}px)`]: {
70    gridTemplateColumns: 'minmax(0, 1fr)',
71    gridAutoRows: 'auto',
72  },
73});
74
75const codeBlockConnectedWrapperStyle = css({
76  [`@media screen and (min-width: ${breakpoints.large}px)`]: {
77    gridGap: 0,
78
79    '> div:nth-of-type(odd)': {
80      '> div': {
81        borderRight: 0,
82        borderTopRightRadius: 0,
83        borderBottomRightRadius: 0,
84      },
85    },
86
87    '> div:nth-of-type(even)': {
88      '> div': {
89        borderTopLeftRadius: 0,
90        borderBottomLeftRadius: 0,
91      },
92    },
93  },
94});
95
96const snippetWrapperStyle = css({
97  [`@media screen and (max-width: ${breakpoints.large}px)`]: {
98    marginBottom: 0,
99
100    '&:last-of-type': {
101      marginBottom: spacing[4],
102    },
103  },
104});
105