Skip to content

Commit

Permalink
Add Custom Link Element Prop (#72)
Browse files Browse the repository at this point in the history
* Added hooks for using custom links

* Added custom link context hook

* Added optional prop in layout component

* Updated package.json
  • Loading branch information
Harry-Ross authored Feb 14, 2024
1 parent 2c86220 commit 17f4fe7
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 13 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ export function getStaticProps() {
| `url` | `string` | The URL of the menu bar item. | No |
| `searchUrl` | `string` | The absolute URL the search takes you to. If not provided, will default to the host address. i.e. for SSW <www.ssw.com.au> | No |
| `rightSideActionsOverride` | `() => JSX.Element` | The component to replace the "Call Us" and search buttons that are displayed by default on the right side of the menu. | No |
| `linkComponent` | <code>React.FC<{<br>&nbsp;href: string;<br>&nbsp;className?: string;<br>&nbsp;title?: string;<br>&nbsp;onClick?: () => void;<br>&nbsp;children?: React.ReactNode;<br>}></code> | The component to use for the links in the menu. i.e. `<Link>` from `next/link` or `gatsby` | No |




## How to contribute?
Expand Down
4 changes: 3 additions & 1 deletion lib/components/CountryDropdown/CountryDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";
import { Popover, Transition } from "@headlessui/react";
import { Fragment, useEffect, useState } from "react";
import { useLinkComponent } from "../../hooks/useLinkComponent";
import { Countries } from "../../types/country";
import { cx } from "../../util/cx";
import { CustomLink } from "../CustomLink";
import { Flag } from "../Flag";

const websites: { country: Countries; url: string }[] = [
Expand All @@ -29,6 +29,8 @@ const CountryDropdown = ({ url }: CountryDropdownProps) => {
const [isOpened, setIsOpened] = useState(false);
const [currentCountry, setCurrentCountry] = useState<Countries>("Australia");

const CustomLink = useLinkComponent();

useEffect(() => {
try {
const { hostname } = new URL(url || "");
Expand Down
4 changes: 3 additions & 1 deletion lib/components/DesktopMenu/MenuItemLink.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { CustomLink } from "../CustomLink";
import { useLinkComponent } from "../../hooks/useLinkComponent";

type MenuItemLinkProps = {
name: string;
href: string;
};

export const MenuItemLink = ({ name, href }: MenuItemLinkProps) => {
const CustomLink = useLinkComponent();

return (
<CustomLink
href={href}
Expand Down
13 changes: 10 additions & 3 deletions lib/components/MegaMenuLayout/MegaMenuLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Bars3Icon } from "@heroicons/react/24/outline";
import type { ClassValue } from "clsx";
import React, { useState } from "react";
import {
LinkComponentType,
useLinkComponent,
} from "../../hooks/useLinkComponent";
import { LinkProvider } from "../../hooks/useLinkComponent/components";
import { useMenuItems } from "../../hooks/useMenuItems";
import { NavMenuGroup } from "../../types/megamenu";
import { DEFAULT_URL } from "../../util/constants";
import { cx } from "../../util/cx";
import { CustomLink } from "../CustomLink";
import DesktopMenu from "../DesktopMenu/DesktopMenu";
import { Logo } from "../Logo";
import MobileMenu from "../MobileMenu/MobileMenu";
Expand All @@ -19,6 +23,7 @@ export type MegaMenuWrapperProps = {
subtitle?: string;
searchUrl?: string;
rightSideActionsOverride?: () => JSX.Element;
linkComponent?: LinkComponentType;
} & React.PropsWithChildren &
(Tagline | Title);

Expand All @@ -40,16 +45,18 @@ const MegaMenuLayout: React.FC<MegaMenuWrapperProps> = ({
subtitle,
searchUrl = DEFAULT_URL,
menuBarItems,
linkComponent,
rightSideActionsOverride,
}) => {
const [isMobileMenuOpen, setMobileMenuOpen] = useState(false);

const { menuItems } = useMenuItems(menuBarItems);
const CustomLink = useLinkComponent();

const RightSideActions = rightSideActionsOverride;

return (
<>
<LinkProvider linkComponent={linkComponent}>
<div
className={cx(
className,
Expand Down Expand Up @@ -122,7 +129,7 @@ const MegaMenuLayout: React.FC<MegaMenuWrapperProps> = ({
) : (
<PhoneButton className="flex-grow pb-4 sm:hidden" />
)}
</>
</LinkProvider>
);
};

Expand Down
4 changes: 3 additions & 1 deletion lib/components/MobileMenu/MobileMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Dialog } from "@headlessui/react";
import { ChevronRightIcon } from "@heroicons/react/24/solid";
import React from "react";
import { useLinkComponent } from "../../hooks/useLinkComponent";
import { NavMenuGroup } from "../../types/megamenu";
import { CustomLink } from "../CustomLink";
import { MegaIcon } from "../MegaIcon";
import SubMenuGroup from "../SubMenuGroup/SubMenuGroup";

Expand Down Expand Up @@ -78,6 +78,8 @@ const MenuBarItems: React.FC<{
menuBarItems: NavMenuGroup[];
setSelectedMenuItem: (item: NavMenuGroup) => void;
}> = ({ menuBarItems, setSelectedMenuItem }) => {
const CustomLink = useLinkComponent();

return (
<div className="-my-6 divide-y divide-gray-500/10 pl-6">
<div className="space-y-2">
Expand Down
4 changes: 3 additions & 1 deletion lib/components/PhoneButton/PhoneButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { isMobile } from "react-device-detect";
// Fix for Next.js as per https://github.com/react-icons/react-icons/issues/821#issuecomment-1747679972
import { FaPhoneAlt } from "react-icons/fa/index.js";
import { useLinkComponent } from "../../hooks/useLinkComponent";
import { cx } from "../../util/cx";
import { CustomLink } from "../CustomLink";

type PhoneButtonProps = {
className?: string;
hideMobile?: boolean;
};

export const PhoneButton = ({ className }: PhoneButtonProps) => {
const CustomLink = useLinkComponent();

const url = isMobile
? "tel:+61299533000"
: "https://ssw.com.au/company/contact-us";
Expand Down
13 changes: 9 additions & 4 deletions lib/components/SubMenuGroup/SubMenuGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";
import React, { useContext } from "react";
import { useLinkComponent } from "../../hooks/useLinkComponent";
import {
NavMenuColumn,
NavMenuColumnGroup,
Expand Down Expand Up @@ -101,9 +102,10 @@ const LinkItem: React.FC<{ link: NavMenuColumnGroupItem }> = ({
link: { name, url, description, icon, iconImg },
}) => {
const close = useContext(ClosePopoverContext);
const CustomLink = useLinkComponent();

return (
<a
<CustomLink
href={url || ""}
className={cx(
"flex items-start gap-x-3 rounded-md bg-white hover:bg-gray-100 focus:outline-none",
Expand Down Expand Up @@ -137,25 +139,28 @@ const LinkItem: React.FC<{ link: NavMenuColumnGroupItem }> = ({
)}
</span>
</div>
</a>
</CustomLink>
);
};

const ViewAllLink: React.FC<{ href?: string; name?: string }> = ({
name,
href,
}) => {
const CustomLink = useLinkComponent();

if (!name || !href) {
return <></>;
}

return (
<div className="flex grow flex-col-reverse items-end self-end pt-4">
<a
<CustomLink
href={href}
className="rounded-md px-3 py-1 text-sm font-semibold leading-6 text-ssw-red hover:bg-ssw-red hover:text-white"
>
{name} &rarr;
</a>
</CustomLink>
</div>
);
};
Expand Down
4 changes: 3 additions & 1 deletion lib/components/SubMenuGroup/SubMenuWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";
import React from "react";
import { useLinkComponent } from "../../hooks/useLinkComponent";
import { SidebarItem } from "../../types/megamenu";
import { CustomLink } from "../CustomLink";
import { AvailableIcons, MegaIcon } from "../MegaIcon";
import FeaturedCard from "./FeaturedCard";

Expand All @@ -10,6 +10,8 @@ interface SubMenuWidgetProps {
}

const SubMenuWidget: React.FC<SubMenuWidgetProps> = ({ item }) => {
const CustomLink = useLinkComponent();

switch (item.widgetType) {
case "featured": {
return (
Expand Down
33 changes: 33 additions & 0 deletions lib/hooks/useLinkComponent/components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ReactNode, createContext } from "react";
import type { LinkComponentType } from "./index";

const defaultLinkComponent: LinkComponentType = ({
href,
className,
children,
}) => {
return (
<a href={href} className={className}>
{children}
</a>
);
};

export const LinkContext =
createContext<LinkComponentType>(defaultLinkComponent);

type LinkProviderProps = {
linkComponent?: LinkComponentType;
children?: ReactNode;
};

export const LinkProvider = ({
children,
linkComponent = defaultLinkComponent,
}: LinkProviderProps) => {
return (
<LinkContext.Provider value={linkComponent}>
{children}
</LinkContext.Provider>
);
};
13 changes: 13 additions & 0 deletions lib/hooks/useLinkComponent/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { useContext } from "react";
import { LinkContext } from "./components";

export type LinkComponentType = React.FC<{
href: string;
className?: string;
title?: string;
onClick?: () => void;
children?: React.ReactNode;
}>;

export const useLinkComponent = () =>
useContext<LinkComponentType>(LinkContext);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ssw.megamenu",
"version": "4.1.2",
"version": "4.2.0",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.es.js",
Expand Down

0 comments on commit 17f4fe7

Please sign in to comment.