Skip to content

Commit

Permalink
create Next link components for mui
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-burel committed Oct 11, 2021
1 parent 0601119 commit 4934ab7
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 13 deletions.
4 changes: 0 additions & 4 deletions packages/@vulcanjs/next-material-ui/index.ts

This file was deleted.

113 changes: 113 additions & 0 deletions packages/@vulcanjs/next-mui/components/Link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import * as React from "react";
import clsx from "clsx";
import { useRouter } from "next/router";
import NextLink, { LinkProps as NextLinkProps } from "next/link";
import MuiLink, { LinkProps as MuiLinkProps } from "@mui/material/Link";
import { styled } from "@mui/material/styles";

// Add support for the sx prop for consistency with the other branches.
const Anchor = styled("a")({});

export interface NextLinkComposedProps
extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href">,
Omit<NextLinkProps, "href" | "as"> {
to: NextLinkProps["href"];
linkAs?: NextLinkProps["as"];
href?: NextLinkProps["href"];
}

export const NextLinkComposed = React.forwardRef<
HTMLAnchorElement,
NextLinkComposedProps
>(function NextLinkComposed(props, ref) {
const {
to,
linkAs,
href,
replace,
scroll,
shallow,
prefetch,
locale,
...other
} = props;

return (
<NextLink
href={to}
prefetch={prefetch}
as={linkAs}
replace={replace}
scroll={scroll}
shallow={shallow}
passHref
locale={locale}
>
<Anchor ref={ref} {...other} />
</NextLink>
);
});

export type LinkProps = {
activeClassName?: string;
as?: NextLinkProps["as"];
href: NextLinkProps["href"];
noLinkStyle?: boolean;
} & Omit<NextLinkComposedProps, "to" | "linkAs" | "href"> &
Omit<MuiLinkProps, "href">;

// A styled version of the Next.js Link component:
// https://nextjs.org/docs/#with-link
const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link(
props,
ref
) {
const {
activeClassName = "active",
as: linkAs,
className: classNameProps,
href,
noLinkStyle,
role, // Link don't have roles.
...other
} = props;

const router = useRouter();
const pathname = typeof href === "string" ? href : href.pathname;
const className = clsx(classNameProps, {
[activeClassName]: router.pathname === pathname && activeClassName,
});

const isExternal =
typeof href === "string" &&
(href.indexOf("http") === 0 || href.indexOf("mailto:") === 0);

if (isExternal) {
if (noLinkStyle) {
// @ts-expect-error
return <Anchor className={className} href={href} ref={ref} {...other} />;
}

// @ts-expect-error
return <MuiLink className={className} href={href} ref={ref} {...other} />;
}

if (noLinkStyle) {
return (
<NextLinkComposed className={className} ref={ref} to={href} {...other} />
);
}

return (
<MuiLink
component={NextLinkComposed}
linkAs={linkAs}
className={className}
ref={ref}
to={href}
{...other}
/>
);
});

export default Link;
50 changes: 50 additions & 0 deletions packages/@vulcanjs/next-mui/components/NextMuiButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
Button,
ButtonProps,
ListItemButton,
ListItemButtonProps,
} from "@mui/material";
import NextLink, { LinkProps as NextLinkProps } from "next/link";
import pick from "lodash/pick";
import omit from "lodash/omit";

const nextLinkProps: Array<keyof NextLinkProps> = [
"href",
"as",
"replace",
"scroll",
"shallow",
"passHref",
"prefetch",
"locale",
];
/**
* Button to be used when using href and pointing toward a local page
*/
export const NextMuiButton = ({
children,
...props
}: ButtonProps & NextLinkProps) => {
const linkProps = pick(props, nextLinkProps);
const buttonProps = omit(props, nextLinkProps);
return (
<Button {...buttonProps}>
<NextLink {...linkProps}>{children}</NextLink>
</Button>
);
};
/**
* Button to be used when using href and pointing toward a local page
*/
export const NextMuiListItemButton = ({
children,
...props
}: ListItemButtonProps & NextLinkProps) => {
const linkProps = pick(props, nextLinkProps);
const buttonProps = omit(props, nextLinkProps);
return (
<ListItemButton {...buttonProps}>
<NextLink {...linkProps}>{children}</NextLink>
</ListItemButton>
);
};
21 changes: 21 additions & 0 deletions packages/@vulcanjs/next-mui/components/stories/Link.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import { NextLinkComposed, NextLinkComposedProps } from "../Link";
// import { action } from "@storybook/addon-actions";
import { Story, Meta } from "@storybook/react";

export default {
title: "next-mui/NextMuiLink",
component: NextLinkComposed,
// decorators: [(Story) => <div><Story /></div>,
args: {},
} as Meta<NextLinkComposedProps>;

const Template: Story<NextLinkComposedProps> = (args) => (
<NextLinkComposed {...args} />
);

// please keep this default story as is => it serves as a basis for Jest unit tests as well
export const DefaultNextMuiLink = Template.bind({});

// export const Basic = Template.bind({})
// Basic.args = { ...DefaultNextMuiLink.args/*, add other props here */ }
8 changes: 8 additions & 0 deletions packages/@vulcanjs/next-mui/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export * from "./emotion/createEmotionCache";

export { default as Link } from "./components/Link"; // deprecated alias
export { default as NextMuiLink } from "./components/Link"; // recommanded alias to use
export {
NextMuiButton,
NextMuiListItemButton,
} from "./components/NextMuiButton"; // other components accepting links
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@vulcanjs/next-material-ui",
"name": "@vulcanjs/next-mui",
"version": "0.0.1",
"description": "Vulcan Next Material UI binding",
"main": "./dist/index.js",
Expand Down
File renamed without changes.
7 changes: 5 additions & 2 deletions src/components/vn/learn/Steps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useMulti } from "@vulcanjs/react-hooks";
import { User } from "~/models/user";
import { UserType } from "~/models/user";
import { useRouter } from "next/router";
import { NextMuiListItemButton } from "@vulcanjs/next-mui";

/**
* @client-only
Expand Down Expand Up @@ -84,12 +85,14 @@ export const Steps = () => {
{steps.map((step, stepIdx) => {
return (
<ListItem key={step.name}>
<ListItemButton
{/** Since steps are pointing to a local page, we need a Next link */}
<NextMuiListItemButton
href={step.path}
disabled={stepIdx > maxStep}
selected={stepIdx === currentStep}
>
{step.name}
</ListItemButton>
</NextMuiListItemButton>
</ListItem>
);
})}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ReactElement, ReactNode } from "react";
// Comment if you don't need i18n
import { appWithTranslation } from "~/lib/i18n";
// Comment if you don't need Material UI
import { createEmotionCache } from "@vulcanjs/next-material-ui";
import { createEmotionCache } from "@vulcanjs/next-mui";
import { MuiThemeProvider } from "~/components/providers";

import Head from "next/head";
Expand Down
2 changes: 1 addition & 1 deletion src/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import theme from "~/lib/style/defaultTheme";
import {
getAppEnhancer as getMuiAppEnhancer,
//getMuiDocumentInitialProps,
} from "@vulcanjs/next-material-ui/server";
} from "@vulcanjs/next-mui/server";
import { i18nPropsFromCtx, DocumentLanguageProps } from "~/lib/i18n";

interface VNSDocumentProps {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/admin/crud/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import models from "~/models";
import { PageLayout } from "~/components/layout";
import { Typography, List, ListItem } from "@mui/material";
import { Link } from "@vulcanjs/next-material-ui";
import { Link } from "@vulcanjs/next-mui";

const ModelsPage = () => {
return (
Expand Down
2 changes: 1 addition & 1 deletion src/pages/admin/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { useUser } from "~/components/account/hooks";
import { NextMuiLink } from "@vulcanjs/next-material-ui";
import { NextMuiLink } from "@vulcanjs/next-mui";
import { Typography } from "@mui/material";
import { PageLayout } from "~/components/layout";
import { routes } from "~/lib/routes";
Expand Down
2 changes: 1 addition & 1 deletion src/pages/docs/[[...filePath]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import renderToString from "next-mdx-remote/render-to-string";
import hydrate from "next-mdx-remote/hydrate";
import path from "path";
import { getMdxPaths, MdxPath } from "@vulcanjs/mdx";
import { Link as NextLink } from "@vulcanjs/next-material-ui";
import { Link as NextLink } from "@vulcanjs/next-mui";
import { promises as fsPromises, lstatSync, existsSync } from "fs";
import { List, ListItem, Link, Typography } from "@mui/material";
import matter from "gray-matter";
Expand Down
2 changes: 1 addition & 1 deletion src/pages/vn/debug/mui.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { Box, Button, Typography, Container } from "@mui/material"; // Next has tree shaking
import { Link } from "@vulcanjs/next-material-ui";
import { Link } from "@vulcanjs/next-mui";

export default function MuiPage() {
return (
Expand Down

0 comments on commit 4934ab7

Please sign in to comment.