xref: /expo/docs/ui/components/Sidebar/Sidebar.tsx (revision 9de0c686)
1import { css } from '@emotion/react';
2import { theme } from '@expo/styleguide';
3import { spacing, breakpoints } from '@expo/styleguide-base';
4import type { PropsWithChildren, ComponentType } from 'react';
5
6import { SidebarGroup, SidebarSection, VersionSelector } from './index';
7
8import { NavigationType, NavigationRoute } from '~/types/common';
9
10const STYLES_SIDEBAR = css`
11  padding: ${spacing[4]}px;
12  width: 280px;
13  position: relative;
14  background-color: ${theme.background.default};
15
16  @media screen and (max-width: ${breakpoints.medium + 124}px) {
17    width: 100%;
18  }
19`;
20
21const STYLES_SIDEBAR_FADE = css`
22  background: linear-gradient(${theme.background.default}, transparent);
23  height: 30px;
24  width: 274px;
25  position: fixed;
26  margin-top: -${spacing[4]}px;
27  left: 0;
28  z-index: 10;
29  pointer-events: none;
30
31  @media screen and (max-width: ${breakpoints.medium + 124}px) {
32    display: none;
33  }
34`;
35
36type SidebarProps = PropsWithChildren<{
37  routes?: NavigationRoute[];
38}>;
39
40export type SidebarNodeProps = {
41  route: NavigationRoute;
42  parentRoute?: NavigationRoute;
43};
44
45export const Sidebar = ({ routes = [] }: SidebarProps) => {
46  const renderTypes: Record<NavigationType, ComponentType<SidebarNodeProps> | null> = {
47    section: SidebarGroup,
48    group: SidebarSection,
49    page: null, // Pages are rendered inside groups and should not be rendered directly
50  };
51
52  return (
53    <nav css={STYLES_SIDEBAR} data-sidebar>
54      <div css={[STYLES_SIDEBAR_FADE]} />
55      <VersionSelector />
56      {routes.map(route => {
57        const Component = renderTypes[route.type];
58        return !!Component && <Component key={`${route.type}-${route.name}`} route={route} />;
59      })}
60    </nav>
61  );
62};
63