From 17f4fe71397e01ecae6a6b01223147f6d9b0efd4 Mon Sep 17 00:00:00 2001 From: "Harry Ross [SSW]" Date: Wed, 14 Feb 2024 11:05:52 +1100 Subject: [PATCH] Add Custom Link Element Prop (#72) * Added hooks for using custom links * Added custom link context hook * Added optional prop in layout component * Updated package.json --- README.md | 3 ++ .../CountryDropdown/CountryDropdown.tsx | 4 ++- lib/components/DesktopMenu/MenuItemLink.tsx | 4 ++- .../MegaMenuLayout/MegaMenuLayout.tsx | 13 ++++++-- lib/components/MobileMenu/MobileMenu.tsx | 4 ++- lib/components/PhoneButton/PhoneButton.tsx | 4 ++- lib/components/SubMenuGroup/SubMenuGroup.tsx | 13 +++++--- lib/components/SubMenuGroup/SubMenuWidget.tsx | 4 ++- lib/hooks/useLinkComponent/components.tsx | 33 +++++++++++++++++++ lib/hooks/useLinkComponent/index.ts | 13 ++++++++ package.json | 2 +- 11 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 lib/hooks/useLinkComponent/components.tsx create mode 100644 lib/hooks/useLinkComponent/index.ts diff --git a/README.md b/README.md index e3f1f67..40cdbef 100644 --- a/README.md +++ b/README.md @@ -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 | 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` | React.FC<{
 href: string;
 className?: string;
 title?: string;
 onClick?: () => void;
 children?: React.ReactNode;
}>
| The component to use for the links in the menu. i.e. `` from `next/link` or `gatsby` | No | + + ## How to contribute? diff --git a/lib/components/CountryDropdown/CountryDropdown.tsx b/lib/components/CountryDropdown/CountryDropdown.tsx index 3d065e3..62716f8 100644 --- a/lib/components/CountryDropdown/CountryDropdown.tsx +++ b/lib/components/CountryDropdown/CountryDropdown.tsx @@ -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 }[] = [ @@ -29,6 +29,8 @@ const CountryDropdown = ({ url }: CountryDropdownProps) => { const [isOpened, setIsOpened] = useState(false); const [currentCountry, setCurrentCountry] = useState("Australia"); + const CustomLink = useLinkComponent(); + useEffect(() => { try { const { hostname } = new URL(url || ""); diff --git a/lib/components/DesktopMenu/MenuItemLink.tsx b/lib/components/DesktopMenu/MenuItemLink.tsx index 321a4d6..37c0fa7 100644 --- a/lib/components/DesktopMenu/MenuItemLink.tsx +++ b/lib/components/DesktopMenu/MenuItemLink.tsx @@ -1,4 +1,4 @@ -import { CustomLink } from "../CustomLink"; +import { useLinkComponent } from "../../hooks/useLinkComponent"; type MenuItemLinkProps = { name: string; @@ -6,6 +6,8 @@ type MenuItemLinkProps = { }; export const MenuItemLink = ({ name, href }: MenuItemLinkProps) => { + const CustomLink = useLinkComponent(); + return ( JSX.Element; + linkComponent?: LinkComponentType; } & React.PropsWithChildren & (Tagline | Title); @@ -40,16 +45,18 @@ const MegaMenuLayout: React.FC = ({ subtitle, searchUrl = DEFAULT_URL, menuBarItems, + linkComponent, rightSideActionsOverride, }) => { const [isMobileMenuOpen, setMobileMenuOpen] = useState(false); const { menuItems } = useMenuItems(menuBarItems); + const CustomLink = useLinkComponent(); const RightSideActions = rightSideActionsOverride; return ( - <> +
= ({ ) : ( )} - + ); }; diff --git a/lib/components/MobileMenu/MobileMenu.tsx b/lib/components/MobileMenu/MobileMenu.tsx index 9dc18aa..60bfaaa 100644 --- a/lib/components/MobileMenu/MobileMenu.tsx +++ b/lib/components/MobileMenu/MobileMenu.tsx @@ -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"; @@ -78,6 +78,8 @@ const MenuBarItems: React.FC<{ menuBarItems: NavMenuGroup[]; setSelectedMenuItem: (item: NavMenuGroup) => void; }> = ({ menuBarItems, setSelectedMenuItem }) => { + const CustomLink = useLinkComponent(); + return (
diff --git a/lib/components/PhoneButton/PhoneButton.tsx b/lib/components/PhoneButton/PhoneButton.tsx index 560c61b..ed26f61 100644 --- a/lib/components/PhoneButton/PhoneButton.tsx +++ b/lib/components/PhoneButton/PhoneButton.tsx @@ -1,8 +1,8 @@ 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; @@ -10,6 +10,8 @@ type PhoneButtonProps = { }; export const PhoneButton = ({ className }: PhoneButtonProps) => { + const CustomLink = useLinkComponent(); + const url = isMobile ? "tel:+61299533000" : "https://ssw.com.au/company/contact-us"; diff --git a/lib/components/SubMenuGroup/SubMenuGroup.tsx b/lib/components/SubMenuGroup/SubMenuGroup.tsx index aee6638..cd2e23b 100644 --- a/lib/components/SubMenuGroup/SubMenuGroup.tsx +++ b/lib/components/SubMenuGroup/SubMenuGroup.tsx @@ -1,5 +1,6 @@ "use client"; import React, { useContext } from "react"; +import { useLinkComponent } from "../../hooks/useLinkComponent"; import { NavMenuColumn, NavMenuColumnGroup, @@ -101,9 +102,10 @@ const LinkItem: React.FC<{ link: NavMenuColumnGroupItem }> = ({ link: { name, url, description, icon, iconImg }, }) => { const close = useContext(ClosePopoverContext); + const CustomLink = useLinkComponent(); return ( - = ({ )}
- + ); }; @@ -145,17 +147,20 @@ const ViewAllLink: React.FC<{ href?: string; name?: string }> = ({ name, href, }) => { + const CustomLink = useLinkComponent(); + if (!name || !href) { return <>; } + return ( ); }; diff --git a/lib/components/SubMenuGroup/SubMenuWidget.tsx b/lib/components/SubMenuGroup/SubMenuWidget.tsx index f6f83e4..edf20ff 100644 --- a/lib/components/SubMenuGroup/SubMenuWidget.tsx +++ b/lib/components/SubMenuGroup/SubMenuWidget.tsx @@ -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"; @@ -10,6 +10,8 @@ interface SubMenuWidgetProps { } const SubMenuWidget: React.FC = ({ item }) => { + const CustomLink = useLinkComponent(); + switch (item.widgetType) { case "featured": { return ( diff --git a/lib/hooks/useLinkComponent/components.tsx b/lib/hooks/useLinkComponent/components.tsx new file mode 100644 index 0000000..ccf2626 --- /dev/null +++ b/lib/hooks/useLinkComponent/components.tsx @@ -0,0 +1,33 @@ +import { ReactNode, createContext } from "react"; +import type { LinkComponentType } from "./index"; + +const defaultLinkComponent: LinkComponentType = ({ + href, + className, + children, +}) => { + return ( + + {children} + + ); +}; + +export const LinkContext = + createContext(defaultLinkComponent); + +type LinkProviderProps = { + linkComponent?: LinkComponentType; + children?: ReactNode; +}; + +export const LinkProvider = ({ + children, + linkComponent = defaultLinkComponent, +}: LinkProviderProps) => { + return ( + + {children} + + ); +}; diff --git a/lib/hooks/useLinkComponent/index.ts b/lib/hooks/useLinkComponent/index.ts new file mode 100644 index 0000000..4c135bd --- /dev/null +++ b/lib/hooks/useLinkComponent/index.ts @@ -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(LinkContext); diff --git a/package.json b/package.json index 10ad530..dc9ee29 100644 --- a/package.json +++ b/package.json @@ -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",