diff --git a/apps/docs/components/ExampleSideNav.tsx b/apps/docs/components/ExampleSideNav.tsx index 8414bb1b..04c4b75c 100644 --- a/apps/docs/components/ExampleSideNav.tsx +++ b/apps/docs/components/ExampleSideNav.tsx @@ -4,16 +4,19 @@ import { SideNav, SideNavItem, SideNavItemGroup } from '@enterwell/react-ui'; import { Button } from '@mui/material'; import { Stack } from '@mui/system'; import Image from 'next/image'; -import { useSearchParams } from 'next/navigation'; +import { useRouter, useSearchParams } from 'next/navigation'; export function ExampleSideNav() { - const params = useSearchParams(); - const selectedItem = params.get('item'); - const show = params.get('show') === 'true'; + const router = useRouter(); + const searchParams = useSearchParams(); + const selectedItem = searchParams.get('item'); + const show = searchParams.get('show') === 'true'; function setShow(show: boolean) { - const url = new URL(window.location.href); - url.searchParams.set('show', show.toString()); - window.history.pushState({}, '', url.toString()); + const query = new URLSearchParams(Array.from(searchParams.entries())); + if (!show) + query.delete('show'); + else query.set('show', show.toString()); + router.push(`?${query.toString()}`); } return ( diff --git a/packages/react-ui/SideNav/SideNav.tsx b/packages/react-ui/SideNav/SideNav.tsx index e6d3b9cb..0b08b7d4 100644 --- a/packages/react-ui/SideNav/SideNav.tsx +++ b/packages/react-ui/SideNav/SideNav.tsx @@ -1,17 +1,7 @@ -import { AppBar, AppBarProps, Collapse, Drawer, List, ListItemButton, ListItemIcon, ListItemText, Paper, Stack, Theme, Toolbar, Typography, useTheme } from '@mui/material'; +import { AppBar, AppBarProps, Drawer, List, Stack, Toolbar } from '@mui/material'; import useMediaQuery from '@mui/material/useMediaQuery'; -import { PropsWithChildren, ReactNode, createContext, useContext } from 'react'; +import { ReactNode } from 'react'; import { useControllableState } from '@enterwell/react-hooks'; -import { AddOutlined, RemoveOutlined } from '@mui/icons-material'; - -const itemOpacity = 0.7; -const itemHoverOpacity = 0.9; - -function itemBackgroundImageHighlight(theme: Theme, amount = 0.05) { - return theme.palette.mode === "dark" - ? `linear-gradient(180deg, rgba(255,255,255,${amount}) 0%, rgba(255,255,255,${amount}) 100%)` - : `linear-gradient(180deg, rgba(0,0,0,${amount}) 0%, rgba(0,0,0,${amount}) 100%)`; -} /** * The props for the SideNav component @@ -42,8 +32,7 @@ export type SideNavProps = AppBarProps & { */ export function SideNav({ children, sx, width = 230, headerHeight = 65, header, endAdorner, ...rest }: SideNavProps) { const [navOpen, setNavOpen] = useControllableState(false); - const theme = useTheme(); - const isMobile = useMediaQuery(theme.breakpoints.down('md')); + const isMobile = useMediaQuery((theme) => theme.breakpoints.down('md')); const handleClose = () => setNavOpen(false); @@ -118,158 +107,3 @@ export function SideNav({ children, sx, width = 230, headerHeight = 65, header, ); }; - -/** - * The SideNavItemGroup component props. - * @public - */ -type SideNavItemGroupProps = PropsWithChildren<{ - label: string; - expanded?: boolean; - defaultExpanded?: boolean; -}>; - -const SideNavItemGroupContext = createContext({ inGroup: false }); - -/** - * The SideNavItemGroup component. - * - * @param props - The component props. - * @returns The react function component. - * @public - */ -export function SideNavItemGroup({ children, label, expanded: controlledExpanded, defaultExpanded }: SideNavItemGroupProps) { - const [expanded, setExpanded] = useControllableState(controlledExpanded, defaultExpanded ?? false); - const handleToggleExpand = () => setExpanded(!expanded); - const theme = useTheme(); - - const contextValue = { - inGroup: true - }; - - return ( - <> - - - - {label} - - - {expanded - ? ( - - ) : ( - - )} - - - - - {children} - - - - - ); -} - -/** - * The SideNavItem component props. - * @public - */ -export type SideNavItemProps = PropsWithChildren<{ - href: string; - icon?: ReactNode; - selected?: boolean; -}>; - -/** - * The SideNavItem component - * @param props - The component props - * @returns The react function component. - * @public - */ -export function SideNavItem({ children, href, selected, icon }: SideNavItemProps) { - const groupContext = useContext(SideNavItemGroupContext); - const child = groupContext?.inGroup; - const theme = useTheme(); - - return ( - - {icon && ( - svg': { fill: selected ? 'primaryBase' : 'white' } - }} - > - {icon} - - )} - - - {children} - - - - ); -}; diff --git a/packages/react-ui/SideNav/SideNavItem.tsx b/packages/react-ui/SideNav/SideNavItem.tsx new file mode 100644 index 00000000..6c4e1a11 --- /dev/null +++ b/packages/react-ui/SideNav/SideNavItem.tsx @@ -0,0 +1,77 @@ +import { ListItemButton, ListItemIcon, ListItemText, Typography, useTheme } from '@mui/material'; +import { PropsWithChildren, ReactNode, useContext } from 'react'; +import { SideNavItemGroupContext } from './SideNavItemGroupContext'; +import { itemBackgroundImageHighlight, itemHoverOpacity, itemOpacity } from './shared'; + +/** + * The SideNavItem component props. + * @public + */ +export type SideNavItemProps = PropsWithChildren<{ + href: string; + icon?: ReactNode; + selected?: boolean; +}>; + +/** + * The SideNavItem component + * @param props - The component props + * @returns The react function component. + * @public + */ +export function SideNavItem({ children, href, selected, icon }: SideNavItemProps) { + const groupContext = useContext(SideNavItemGroupContext); + const isInGroup = groupContext?.inGroup; + const theme = useTheme(); + + return ( + + {icon && ( + svg': { fill: selected ? 'primaryBase' : 'white' } + }} + > + {icon} + + )} + + + {children} + + + + ); +}; diff --git a/packages/react-ui/SideNav/SideNavItemGroup.tsx b/packages/react-ui/SideNav/SideNavItemGroup.tsx new file mode 100644 index 00000000..6d5bc8d3 --- /dev/null +++ b/packages/react-ui/SideNav/SideNavItemGroup.tsx @@ -0,0 +1,86 @@ +import { Collapse, List, ListItemButton, ListItemText, Typography, useTheme } from '@mui/material'; +import { PropsWithChildren } from 'react'; +import { useControllableState } from '@enterwell/react-hooks'; +import { AddOutlined, RemoveOutlined } from '@mui/icons-material'; +import { SideNavItemGroupContext } from './SideNavItemGroupContext'; +import { itemBackgroundImageHighlight, itemHoverOpacity, itemOpacity } from './shared'; + +/** + * The SideNavItemGroup component props. + * @public + */ +export type SideNavItemGroupProps = PropsWithChildren<{ + label: string; + expanded?: boolean; + defaultExpanded?: boolean; +}>; + +/** + * The SideNavItemGroup component. + * + * @param props - The component props. + * @returns The react function component. + * @public + */ +export function SideNavItemGroup({ children, label, expanded: controlledExpanded, defaultExpanded }: SideNavItemGroupProps) { + const [expanded, setExpanded] = useControllableState(controlledExpanded, defaultExpanded ?? false); + const handleToggleExpand = () => setExpanded(!expanded); + const theme = useTheme(); + + const contextValue = { + inGroup: true + }; + + return ( + <> + + + + {label} + + + {expanded + ? ( + + ) : ( + + )} + + + + + {children} + + + + + ); +} diff --git a/packages/react-ui/SideNav/SideNavItemGroupContext.ts b/packages/react-ui/SideNav/SideNavItemGroupContext.ts new file mode 100644 index 00000000..96256227 --- /dev/null +++ b/packages/react-ui/SideNav/SideNavItemGroupContext.ts @@ -0,0 +1,3 @@ +import { createContext } from "react"; + +export const SideNavItemGroupContext = createContext({ inGroup: false }); diff --git a/packages/react-ui/SideNav/index.tsx b/packages/react-ui/SideNav/index.tsx index f039eea0..55f9b6e9 100644 --- a/packages/react-ui/SideNav/index.tsx +++ b/packages/react-ui/SideNav/index.tsx @@ -1 +1,3 @@ export * from "./SideNav"; +export * from "./SideNavItemGroup"; +export * from "./SideNavItem"; \ No newline at end of file diff --git a/packages/react-ui/SideNav/shared.ts b/packages/react-ui/SideNav/shared.ts new file mode 100644 index 00000000..9ace7cf7 --- /dev/null +++ b/packages/react-ui/SideNav/shared.ts @@ -0,0 +1,10 @@ +import { Theme } from "@mui/material"; + +export const itemOpacity = 0.7; +export const itemHoverOpacity = 0.9; + +export function itemBackgroundImageHighlight(theme: Theme, amount = 0.05) { + return theme.palette.mode === "dark" + ? `linear-gradient(180deg, rgba(255,255,255,${amount}) 0%, rgba(255,255,255,${amount}) 100%)` + : `linear-gradient(180deg, rgba(0,0,0,${amount}) 0%, rgba(0,0,0,${amount}) 100%)`; + } \ No newline at end of file diff --git a/packages/react-ui/temp/react-ui.api.md b/packages/react-ui/temp/react-ui.api.md index 15401244..b814753a 100644 --- a/packages/react-ui/temp/react-ui.api.md +++ b/packages/react-ui/temp/react-ui.api.md @@ -200,11 +200,16 @@ export function SideNav({ children, sx, width, headerHeight, header, endAdorner, // @public export function SideNavItem({ children, href, selected, icon }: SideNavItemProps): react_jsx_runtime.JSX.Element; -// Warning: (ae-forgotten-export) The symbol "SideNavItemGroupProps" needs to be exported by the entry point index.d.ts -// // @public export function SideNavItemGroup({ children, label, expanded: controlledExpanded, defaultExpanded }: SideNavItemGroupProps): react_jsx_runtime.JSX.Element; +// @public +export type SideNavItemGroupProps = PropsWithChildren<{ + label: string; + expanded?: boolean; + defaultExpanded?: boolean; +}>; + // @public export type SideNavItemProps = PropsWithChildren<{ href: string;