1import { css } from '@emotion/react';
2import { theme, typography } from '@expo/styleguide';
3import { PropsWithChildren, useContext } from 'react';
4
5import { PageApiVersionContext } from '~/providers/page-api-version';
6import { usePageMetadata } from '~/providers/page-metadata';
7import { Terminal } from '~/ui/components/Snippet';
8import { A } from '~/ui/components/Text';
9
10const STYLES_P = css`
11  line-height: 1.8rem;
12  margin-top: 1.4rem;
13  margin-bottom: 1.4rem;
14  color: ${theme.text.default};
15`;
16
17const STYLES_BOLD = css`
18  font-family: ${typography.fontFaces.medium};
19  font-weight: 400;
20  text-decoration: none;
21  color: ${theme.link.default};
22  :hover {
23    text-decoration: underline;
24  }
25`;
26const STYLES_LINK = css`
27  text-decoration: none;
28  color: ${theme.link.default};
29  :hover {
30    text-decoration: underline;
31  }
32`;
33
34type InstallSectionProps = PropsWithChildren<{
35  packageName: string;
36  hideBareInstructions?: boolean;
37  cmd?: string[];
38  href?: string;
39}>;
40
41const getPackageLink = (packageNames: string) =>
42  `https://github.com/expo/expo/tree/main/packages/${packageNames.split(' ')[0]}`;
43
44function getInstallCmd(packageName: string) {
45  return `$ npx expo install ${packageName}`;
46}
47
48const InstallSection = ({
49  packageName,
50  hideBareInstructions = false,
51  cmd = [getInstallCmd(packageName)],
52  href = getPackageLink(packageName),
53}: InstallSectionProps) => {
54  const { sourceCodeUrl } = usePageMetadata();
55  const { version } = useContext(PageApiVersionContext);
56
57  // Recommend just `expo install` for SDK 43, 44, and 45.
58  // TODO: remove this when we drop SDK 45 from docs
59  if (version.startsWith('v43') || version.startsWith('v44') || version.startsWith('v45')) {
60    if (cmd[0] === getInstallCmd(packageName)) {
61      cmd[0] = cmd[0].replace('npx expo', 'expo');
62    }
63  }
64
65  return (
66    <>
67      <Terminal cmd={cmd} />
68      {hideBareInstructions ? null : (
69        <p css={STYLES_P}>
70          If you're installing this in a{' '}
71          <A css={STYLES_LINK} href="/introduction/managed-vs-bare/#bare-workflow">
72            bare React Native app
73          </A>
74          , you should also follow{' '}
75          <A css={STYLES_BOLD} href={sourceCodeUrl ?? href}>
76            these additional installation instructions
77          </A>
78          .
79        </p>
80      )}
81    </>
82  );
83};
84
85export default InstallSection;
86
87export const APIInstallSection = (props: InstallSectionProps) => {
88  const { packageName } = usePageMetadata();
89  return <InstallSection {...props} packageName={props.packageName ?? packageName} />;
90};
91