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