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