Last active
March 7, 2025 07:50
-
-
Save gsouf/fe6012052542484829bba49fe5f44387 to your computer and use it in GitHub Desktop.
A React component for shopify's remix embedded app that will let opening links in a new tab
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { Button } from '@shopify/polaris'; | |
import { useAppBridge } from '@shopify/app-bridge-react'; | |
import { NavLink, useNavigate } from '@remix-run/react'; | |
const appHandle = "your-app-handle"; | |
/** | |
* `polaris.Link` can't open embedded app's links and `shopify://` links a in a new tab. | |
* This component embables that while keeping it working as usual when no modifier key is pressed when clicking. | |
* | |
* Usage: | |
* `<AdaptiveLink url="/app/page">some page</AdaptiveLink>` | |
* `<AdaptiveLink url="shopify://admin/products/12345">some product</AdaptiveLink>` | |
* | |
* @param {import('@shopify/polaris/build/ts/src/components/Link/Link.js').LinkProps} props | |
* @returns {JSX.Element} | |
*/ | |
export default function AdaptiveLink(props) { | |
const { | |
url: originalUrl, | |
target: originalTarget, | |
children, | |
...otherProps | |
} = props; | |
const shopify = useAppBridge(); | |
const navigate = useNavigate(); | |
// transformed url and target | |
const [url, setUrl] = useState(originalUrl); | |
const [target, setTarget] = useState(originalTarget); | |
// transform original url | |
useEffect(() => { | |
if (originalUrl && typeof originalUrl === "string") { | |
// transform links like `shopify://admin/...` to an absolute https url to the admin | |
if (originalUrl.startsWith("shopify://admin/")) { | |
const adminUrl = originalUrl.substring(16); | |
const shopName = shopify.config.shop.split(".")[0]; | |
const newUrl = `https://admin.shopify.com/store/${shopName}/${adminUrl}`; | |
setUrl(newUrl); | |
setTarget(originalTarget || "_top"); | |
return; | |
} else if ( | |
!originalUrl.startsWith("//") && | |
!originalUrl.startsWith("https://") | |
) { | |
const shopName = shopify.config.shop.split(".")[0]; | |
const baseUrl = `https://admin.shopify.com/store/${shopName}/apps/${appHandle}/`; | |
// remove first slash from original url | |
const newPath = originalUrl.startsWith("/") | |
? originalUrl.substring(1) | |
: originalUrl; | |
const newUrl = new URL(newPath, baseUrl).href; | |
setUrl(newUrl); | |
setTarget(originalTarget); | |
return; | |
} | |
} | |
// otherwise reset values | |
setUrl(originalUrl); | |
setTarget(originalTarget); | |
}, [originalUrl, originalTarget]); | |
// Forward props to polaris.Link | |
// onClick: if no modifier key is pressed use useNavigate to use router's navigation | |
// otherwise, because we use an absolute in a.href the browser will be able to open the url in a new tab, | |
// also keeps access to right click>open in a new tab | |
return ( | |
<Link | |
{...otherProps} | |
onClick={(e) => { | |
if (!e.shiftKey && !e.ctrlKey && !e.metaKey && !e.altKey) { | |
// ignore shopify:// links | |
if (originalUrl && !originalUrl.startsWith("shopify://admin")) { | |
e.preventDefault(); | |
navigate(originalUrl); | |
} | |
} | |
}} | |
url={url} | |
target={target} | |
> | |
{children} | |
</Link> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment