Skip to content

Commit 09d0c2a

Browse files
authored
Merge pull request #6 from ameshkin/feature/react-router
sadf
2 parents 437615c + 657c6f4 commit 09d0c2a

5 files changed

Lines changed: 75 additions & 14 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
> MUI 7 Breadcrumbs with **Next.js Link** support, optional **URL-based generation**, and **built-in SEO microdata**. Router-agnostic with zero runtime deps.
44
55
| Item | Value | Badge |
6-
| --------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
6+
| --------------- | ---------------------------------------------------------------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
77
| **GitHub repo** | [github.com/ameshkin/nextcrumbs](https://github.com/ameshkin/nextcrumbs) ||
88
| **CI** | `.github/workflows/ci.yml` | [![CI — main](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/ci.yml?branch=main\&label=ci%20\(main\))](https://github.com/ameshkin/nextcrumbs/actions/workflows/ci.yml) [![CI — dev](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/ci.yml?branch=dev\&label=ci%20\(dev\))](https://github.com/ameshkin/nextcrumbs/actions/workflows/ci.yml) |
99
| **npm package** | [@ameshkin/nextcrumbs](https://www.npmjs.com/package/@ameshkin/nextcrumbs) | [![npm](https://img.shields.io/npm/v/@ameshkin/nextcrumbs.svg)](https://www.npmjs.com/package/@ameshkin/nextcrumbs) |
10-
| **Install** | `npm i @ameshkin/nextcrumbs` | [![install test](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/install.yml?branch=main\&label=install%20test)](https://github.com/ameshkin/nextcrumbs/actions/workflows/install.yml) |
10+
| **Install** | `npm i @ameshkin/nextcrumbs` | [![install test](https://img.shields.io/github/actions/workflow/status/ameshkin/nextcrumbs/ci-main.yml?branch=main\&label=install%20test)](https://github.com/ameshkin/nextcrumbs/actions/workflows/ci-main.yml) |
1111
| **Peer deps** | `@mui/material@^7`, `@mui/icons-material@^7`, `react@>=18`, `react-dom@>=18` | ![peer deps](https://img.shields.io/badge/peer_deps-MUI%207%20%7C%20Icons%207%20%7C%20React%2018-blue) |
1212
| **Types** | TypeScript | ![types](https://img.shields.io/badge/types-TypeScript-blue.svg) |
1313
| **License** | MIT | [![license](https://img.shields.io/badge/license-MIT-black.svg)](LICENSE) |

package-lock.json

Lines changed: 14 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@ameshkin/nextcrumbs",
3-
"version": "0.1.0",
3+
"version": "0.1.2",
44
"description": "MUI 7 breadcrumbs with Next.js Link support, optional URL auto-generation, and SEO microdata.",
55
"license": "MIT",
66
"type": "module",
@@ -60,6 +60,6 @@
6060
"funding": { "type": "github", "url": "https://github.com/sponsors/ameshkin" },
6161
"engines": { "node": ">=20.19 <21 || >=22.12" },
6262
"packageManager": "npm@10.5.0",
63-
"keywords": ["mui", "breadcrumbs", "nextjs", "react", "material-ui", "seo", "schema.org", "app router"],
63+
"keywords": ["mui", "breadcrumbs", "nextjs", "react", "material-ui", "seo", "schema.org", "app router", "react router"],
6464
"publishConfig": { "access": "public" }
6565
}

src/Breadcrumbs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export default function Breadcrumbs({
9797
}) => (
9898
<Box component="span" sx={sxJoin(defaultContentSx, contentSx)} title={title || label}>
9999
{icon && <Box component="span" sx={iconSx}>{icon}</Box>}
100-
<Box component="span" sx={labelSx}>{label}</Box>
100+
<Typography component="span" sx={labelSx}>{label}</Typography>
101101
</Box>
102102
);
103103

src/hooks/useReactRouterBreadcrumbs.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,61 @@
1111
*/
1212
import * as React from "react"
1313
import type { ReactNode } from "react"
14-
import { useLocation } from "react-router-dom"
14+
15+
// Lazy import pattern to avoid requiring react-router-dom when not used
16+
// We use a function that accesses the module at runtime to avoid
17+
// webpack trying to resolve it at build time when it's not installed
18+
let useLocationHook: (() => { pathname: string }) | null = null
19+
20+
function getUseLocation(): () => { pathname: string } {
21+
if (useLocationHook) return useLocationHook
22+
23+
// Access react-router-dom dynamically using a pattern that's harder
24+
// for webpack to statically analyze. We construct the module name
25+
// in a way that makes it less obvious to static analysis.
26+
try {
27+
// Split the module name to make it harder for webpack to detect
28+
const parts = ["react", "router", "dom"]
29+
const mod = parts.join("-")
30+
31+
// Try to access the module - this will work if it's available
32+
// @ts-ignore - accessing optional dependency dynamically
33+
let routerModule: any = null
34+
35+
// Try CommonJS require (for Node.js/CommonJS environments)
36+
if (typeof require !== 'undefined') {
37+
try {
38+
routerModule = require(mod)
39+
} catch {
40+
// require failed, module not available
41+
}
42+
}
43+
44+
// For ESM environments, the module should be available through
45+
// normal module resolution if installed. Since we can't use
46+
// dynamic import() synchronously, we rely on the consuming
47+
// project to have it available or configure webpack appropriately.
48+
if (!routerModule) {
49+
throw new Error("react-router-dom not available")
50+
}
51+
52+
if (!routerModule.useLocation || typeof routerModule.useLocation !== 'function') {
53+
throw new Error("useLocation not found in react-router-dom")
54+
}
55+
56+
const hook = routerModule.useLocation
57+
useLocationHook = hook
58+
return hook
59+
} catch (err: any) {
60+
// If react-router-dom is not available, throw a helpful error
61+
throw new Error(
62+
"useReactRouterBreadcrumbs requires 'react-router-dom' to be installed. " +
63+
"Please install it: npm install react-router-dom. " +
64+
`If you're using Next.js and don't need react-router-dom, you can configure ` +
65+
`webpack to ignore it or install it as a dev dependency.`
66+
)
67+
}
68+
}
1569

1670
export type BreadcrumbItem = {
1771
label: string
@@ -30,6 +84,7 @@ export type ReactRouterBreadcrumbsOptions = {
3084
}
3185

3286
export function useReactRouterBreadcrumbs(options?: ReactRouterBreadcrumbsOptions): BreadcrumbItem[] {
87+
const useLocation = getUseLocation()
3388
const { pathname } = useLocation()
3489
const { rootLabel, basePath, decode = true, exclude = [], mapSegmentLabel } = options || {}
3590

0 commit comments

Comments
 (0)