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