1import { css } from '@emotion/react';
2import { shadows, theme } from '@expo/styleguide';
3import { borderRadius, spacing } from '@expo/styleguide-base';
4import { ChevronDownIcon } from '@expo/styleguide-icons';
5
6import { usePageApiVersion } from '~/providers/page-api-version';
7import versions from '~/public/static/constants/versions.json';
8import { A, LABEL } from '~/ui/components/Text';
9
10const { VERSIONS, LATEST_VERSION, BETA_VERSION } = versions;
11
12// TODO(cedric): move this to a generic select input, so we can reuse it in the color scheme selector
13
14export function ApiVersionSelect() {
15  const { version, hasVersion, setVersion } = usePageApiVersion();
16
17  if (!hasVersion) {
18    return null;
19  }
20
21  return (
22    <div css={containerStyle}>
23      <label className="flex flex-row items-center" htmlFor="api-version-select">
24        <LABEL className="flex">{versionToText(version)}</LABEL>
25        <ChevronDownIcon className="icon-sm shrink-0" />
26      </label>
27      <select
28        id="api-version-select"
29        css={selectStyle}
30        value={version}
31        onChange={event => setVersion(event.target.value)}>
32        {VERSIONS.map(version => (
33          <option key={version} value={version}>
34            {versionToText(version)}
35          </option>
36        ))}
37      </select>
38      {/* Changing versions is a JS only mechanism. To help crawlers find other versions, we add hidden links. */}
39      {VERSIONS.map(version => (
40        <A className="hidden" key={version} href={`/versions/${version}`} />
41      ))}
42    </div>
43  );
44}
45
46function versionToText(version: string): string {
47  if (version === 'unversioned') {
48    return 'Unversioned';
49  } else if (version === 'latest') {
50    return `${versionToText(LATEST_VERSION)} (latest)`;
51  } else if (BETA_VERSION && version === BETA_VERSION.toString()) {
52    return `${versionToText(BETA_VERSION.toString())} (beta)`;
53  }
54  return `SDK ${version.substring(1, 3)}`;
55}
56
57const containerStyle = css({
58  position: 'relative',
59  background: theme.background.default,
60  border: `1px solid ${theme.border.default}`,
61  borderRadius: borderRadius.md,
62  boxShadow: shadows.xs,
63  margin: spacing[4],
64  padding: `${spacing[2]}px ${spacing[3]}px`,
65});
66
67const selectStyle = css({
68  borderRadius: 0,
69  position: 'absolute',
70  width: '100%',
71  height: '100%',
72  top: 0,
73  left: 0,
74  right: 0,
75  bottom: 0,
76  opacity: 0,
77  cursor: 'pointer',
78});
79