Skip to content

Commit

Permalink
fix: make navigator work
Browse files Browse the repository at this point in the history
  • Loading branch information
spaenleh committed Jan 10, 2025
1 parent d3d777e commit 40325aa
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 258 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@mui/lab": "6.0.0-beta.22",
"@mui/material": "6.3.1",
"@sentry/react": "8.48.0",
"@tanstack/react-query": "5.63.0",
"@tanstack/react-router": "1.95.1",
"@tanstack/router-devtools": "1.95.1",
"@tanstack/zod-adapter": "1.95.1",
Expand Down
24 changes: 21 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions src/components/ui/MenuItemLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

import { MenuItem, MenuItemProps } from '@mui/material';

import { LinkComponent, createLink } from '@tanstack/react-router';

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface MUIMenuItemProps extends Omit<MenuItemProps, 'href'> {
// Add any additional props you want to pass to the typography
}

const MUIMenuItemComponent = React.forwardRef<
HTMLAnchorElement,
MUIMenuItemProps
>((props, ref) => {
return <MenuItem component={'a'} ref={ref} {...props} />;
});

const CreatedLinkComponent = createLink(MUIMenuItemComponent);

export const MenuItemLink: LinkComponent<typeof MUIMenuItemComponent> = (
props,
) => {
return <CreatedLinkComponent preload="intent" {...props} />;
};
28 changes: 10 additions & 18 deletions src/components/ui/Navigator/CurrentItemNavigation.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { Typography } from '@mui/material';

import { DiscriminatedItem, ItemType } from '@graasp/sdk';

import { TypographyLink } from '../TypographyLink.js';
import ItemMenu, { ItemMenuProps } from './ItemMenu.js';
import CenterAlignWrapper from './common/CenterAlignWrapper.js';
import NavigationLink from './common/NavigationLink.js';
import { ITEM_NAME_MAX_LENGTH } from './common/constants.js';

export type CurrentItemProps = {
item: DiscriminatedItem;
Expand All @@ -14,35 +11,32 @@ export type CurrentItemProps = {
buildMenuId?: (id: string) => string;
buildMenuItemId?: (id: string) => string;
useChildren: ItemMenuProps['useChildren'];
buildToItemPath: (id: string) => LinkProps['to'];
showArrow: boolean;
};
const CurrentItemNavigation = ({

export function CurrentItemNavigation({
item,
buildBreadcrumbsItemLinkId,
buildToItemPath,
useChildren,
buildIconId,
buildMenuId,
buildMenuItemId,
showArrow,
}: CurrentItemProps): JSX.Element | null => {
}: Readonly<CurrentItemProps>): JSX.Element | null {
return (
<CenterAlignWrapper>
<NavigationLink
<TypographyLink
id={buildBreadcrumbsItemLinkId?.(item.id)}
key={item.id}
to={buildToItemPath(item?.id)}
to="."
params={{ itemId: item.id }}
>
<Typography>
{truncate(item.name, { length: ITEM_NAME_MAX_LENGTH })}
</Typography>
</NavigationLink>
{item.name}
</TypographyLink>
{(item.type === ItemType.FOLDER || showArrow) && (
<ItemMenu
useChildren={useChildren}
itemId={item.id}
buildToItemPath={buildToItemPath}
buildIconId={buildIconId}
buildMenuItemId={buildMenuItemId}
buildMenuId={buildMenuId}
Expand All @@ -51,6 +45,4 @@ const CurrentItemNavigation = ({
)}
</CenterAlignWrapper>
);
};

export default CurrentItemNavigation;
}
32 changes: 8 additions & 24 deletions src/components/ui/Navigator/ExtraItemsMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
import { useState } from 'react';
import { Link } from 'react-router-dom';

import {
IconButton,
IconButtonProps,
Menu,
MenuItem,
Typography,
} from '@mui/material';
import { IconButton, IconButtonProps, Menu, Typography } from '@mui/material';

import { ChevronRightIcon } from 'lucide-react';

import { MenuItemType } from './Navigator.js';
import { MenuItemLink } from '../MenuItemLink';
import { MenuItemType } from './Navigator';

export type ExtraItemsMenuProps = {
icon?: JSX.Element;
menuItems: MenuItemType[];
buildIconId?: (id: string) => string;
buildMenuId?: (itemId: string) => string;
name: string;
};

const Separator = <ChevronRightIcon data-testid="NavigateNextIcon" />;

const ExtraItemsMenu = ({
export function ExtraItemsMenu({
icon = Separator,
menuItems,
buildIconId,
buildMenuId,
name,
}: ExtraItemsMenuProps): JSX.Element => {
}: Readonly<ExtraItemsMenuProps>): JSX.Element {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick: IconButtonProps['onClick'] = (event) => {
Expand All @@ -45,15 +33,13 @@ const ExtraItemsMenu = ({
<IconButton
onClick={handleClick}
aria-haspopup="true"
id={buildIconId?.(name)}
aria-expanded={open ? true : undefined}
>
{icon}
</IconButton>
<Menu
anchorEl={anchorEl}
open={open}
id={buildMenuId?.(name)}
onClose={handleClose}
onClick={handleClose}
anchorOrigin={{
Expand All @@ -66,13 +52,11 @@ const ExtraItemsMenu = ({
}}
>
{menuItems?.map(({ name, path }) => (
<MenuItem key={name} component={Link} to={path}>
<MenuItemLink key={name} to={path}>
<Typography>{name}</Typography>
</MenuItem>
</MenuItemLink>
))}
</Menu>
</>
);
};

export default ExtraItemsMenu;
}
34 changes: 12 additions & 22 deletions src/components/ui/Navigator/ExtraItemsNavigation.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { Box, Typography } from '@mui/material';
import { Box, Stack } from '@mui/material';

import truncate from 'lodash.truncate';

import ExtraItemsMenu from './ExtraItemsMenu.js';
import { MenuItemType } from './Navigator.js';
import CenterAlignWrapper from './common/CenterAlignWrapper.js';
import NavigationLink from './common/NavigationLink.js';
import { ITEM_NAME_MAX_LENGTH } from './common/constants.js';
import { TypographyLink } from '../TypographyLink';
import { ExtraItemsMenu } from './ExtraItemsMenu';
import { MenuItemType } from './Navigator';

export interface ExtraItem {
name: string;
Expand All @@ -15,26 +11,20 @@ export interface ExtraItem {
menuItems?: MenuItemType[];
}

const ExtraItemsNavigation = ({
export function ExtraItemsNavigation({
extraItems,
}: {
}: Readonly<{
extraItems: ExtraItem[];
}): JSX.Element[] | null => {
}>): JSX.Element[] {
return extraItems.map(({ icon, name, path, menuItems }) => (
<CenterAlignWrapper>
<Stack key={name} direction="row" alignItems="center">
<Box display="flex" gap={1}>
{icon}
<NavigationLink to={path}>
<Typography>
{truncate(name, { length: ITEM_NAME_MAX_LENGTH })}
</Typography>
</NavigationLink>
<TypographyLink to={path}>{name}</TypographyLink>
</Box>
{menuItems && menuItems.length > 0 && (
<ExtraItemsMenu menuItems={menuItems} name={name} />
<ExtraItemsMenu menuItems={menuItems} />
)}
</CenterAlignWrapper>
</Stack>
));
};

export default ExtraItemsNavigation;
}
41 changes: 17 additions & 24 deletions src/components/ui/Navigator/ItemMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,35 @@
import type { UseQueryResult } from '@tanstack/react-query';
import { ChevronRightIcon } from 'lucide-react';

import {
IconButton,
IconButtonProps,
Menu,
MenuItem,
Typography,
} from '@mui/material';

import { useState } from 'react';
import { Link, LinkProps } from 'react-router-dom';

import { IconButton, IconButtonProps, Menu, Typography } from '@mui/material';

import { DiscriminatedItem } from '@graasp/sdk';

export const Separator = <ChevronRightIcon data-testid='NavigateNextIcon' />;
import { type UseQueryResult } from '@tanstack/react-query';
import { ChevronRightIcon } from 'lucide-react';

import { MenuItemLink } from '../MenuItemLink';

export const Separator = <ChevronRightIcon data-testid="NavigateNextIcon" />;

export type ItemMenuProps = {
buildIconId?: (id: string) => string;
buildMenuId?: (itemId: string) => string;
buildMenuItemId?: (itemId: string) => string;
buildToItemPath: (itemId: string) => LinkProps['to'];
icon?: JSX.Element;
itemId: string;
useChildren: (...args: unknown[]) => UseQueryResult<DiscriminatedItem[]>;
useChildren: (itemId: string) => UseQueryResult<DiscriminatedItem[]>;
renderArrow?: boolean;
};

const ItemMenu = ({
export function ItemMenu({
buildIconId,
buildMenuId,
buildMenuItemId,
buildToItemPath,
icon = Separator,
itemId,
useChildren,
renderArrow,
}: ItemMenuProps): JSX.Element | null => {
}: Readonly<ItemMenuProps>): JSX.Element | null {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);

Expand All @@ -63,7 +56,7 @@ const ItemMenu = ({
onClick={handleClick}
id={buildIconId?.(itemId)}
aria-controls={open ? buildMenuId?.(itemId) : undefined}
aria-haspopup='true'
aria-haspopup="true"
aria-expanded={open ? true : undefined}
>
{icon}
Expand All @@ -84,18 +77,18 @@ const ItemMenu = ({
}}
>
{items?.map(({ name, id }) => (
<MenuItem
<MenuItemLink
id={buildMenuItemId?.(id)}
key={id}
component={Link}
to={buildToItemPath(id)}
to="/analytics/items/$itemId"
params={{ itemId: id }}
>
<Typography>{name}</Typography>
</MenuItem>
</MenuItemLink>
))}
</Menu>
</>
);
};
}

export default ItemMenu;
Loading

0 comments on commit 40325aa

Please sign in to comment.