@rpcbase/router 0.90.0 → 0.92.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/dist/navigationGuards.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -51,15 +51,28 @@ const useApplyMeta = ({
|
|
|
51
51
|
loadMeta();
|
|
52
52
|
}, [location.pathname, defaultTitle, defaultMeta, pagesMeta]);
|
|
53
53
|
};
|
|
54
|
-
const
|
|
55
|
-
const
|
|
54
|
+
const NAVIGATION_GUARDS_STORE_KEY = "__rpcbaseNavigationGuardsStore";
|
|
55
|
+
const getNavigationGuardsStore = () => {
|
|
56
|
+
const globalAny = globalThis;
|
|
57
|
+
const existing = globalAny[NAVIGATION_GUARDS_STORE_KEY];
|
|
58
|
+
if (existing) {
|
|
59
|
+
return existing;
|
|
60
|
+
}
|
|
61
|
+
const created = {
|
|
62
|
+
guards: /* @__PURE__ */ new Map(),
|
|
63
|
+
listeners: /* @__PURE__ */ new Set()
|
|
64
|
+
};
|
|
65
|
+
globalAny[NAVIGATION_GUARDS_STORE_KEY] = created;
|
|
66
|
+
return created;
|
|
67
|
+
};
|
|
56
68
|
const notify = () => {
|
|
57
|
-
listeners.forEach((listener) => {
|
|
69
|
+
getNavigationGuardsStore().listeners.forEach((listener) => {
|
|
58
70
|
listener();
|
|
59
71
|
});
|
|
60
72
|
};
|
|
61
73
|
const isSameGuard = (a, b) => a.id === b.id && a.enabled === b.enabled && a.priority === b.priority && a.message === b.message && a.blockOnSearch === b.blockOnSearch && a.shouldBlockNavigation === b.shouldBlockNavigation && a.shouldBlockUnload === b.shouldBlockUnload;
|
|
62
74
|
const upsertNavigationGuard = (guard) => {
|
|
75
|
+
const guards = getNavigationGuardsStore().guards;
|
|
63
76
|
const prev = guards.get(guard.id);
|
|
64
77
|
if (prev && isSameGuard(prev, guard)) {
|
|
65
78
|
return;
|
|
@@ -68,13 +81,15 @@ const upsertNavigationGuard = (guard) => {
|
|
|
68
81
|
notify();
|
|
69
82
|
};
|
|
70
83
|
const removeNavigationGuard = (id) => {
|
|
84
|
+
const guards = getNavigationGuardsStore().guards;
|
|
71
85
|
const didDelete = guards.delete(id);
|
|
72
86
|
if (didDelete) {
|
|
73
87
|
notify();
|
|
74
88
|
}
|
|
75
89
|
};
|
|
76
|
-
const getNavigationGuards = () => Array.from(guards.values());
|
|
90
|
+
const getNavigationGuards = () => Array.from(getNavigationGuardsStore().guards.values());
|
|
77
91
|
const subscribeNavigationGuards = (listener) => {
|
|
92
|
+
const listeners = getNavigationGuardsStore().listeners;
|
|
78
93
|
listeners.add(listener);
|
|
79
94
|
return () => {
|
|
80
95
|
listeners.delete(listener);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/loadRoute.tsx","../src/useApplyMeta.tsx","../src/navigationGuards.ts"],"sourcesContent":["import { lazy } from \"react\"\nimport { LoaderFunction } from \"react-router\"\nimport { Loader, LoaderArgs } from \"@rpcbase/client\"\n\n\ntype RouteModule = {\n default: React.ComponentType<unknown>\n loader?: Loader\n}\n\ntype RouteWithLoader = {\n Component: React.LazyExoticComponent<React.ComponentType<unknown>>\n loader?: LoaderFunction\n}\n\nexport const loadRoute = (importPromise: Promise<RouteModule>): RouteWithLoader => {\n const Component = lazy(async () => {\n const module = await importPromise\n return { default: module.default }\n })\n\n const loader = async (args: LoaderArgs) => {\n const module = await importPromise\n if (!module.loader) return null\n return module.loader(args)\n }\n\n return { Component, loader: loader as unknown as LoaderFunction }\n}\n","import { useEffect } from \"react\"\nimport { useLocation } from \"react-router\"\n\n\ntype MetaAttributeValue = string | number | boolean | undefined\ntype MetaEntry = Record<string, MetaAttributeValue>\n\ntype PageMeta = {\n title: string\n meta: MetaEntry[]\n}\n\n\nexport const useApplyMeta = ({\n defaultTitle = \"\",\n defaultMeta = [],\n pagesMeta = {}\n}: {\n defaultTitle?: string\n defaultMeta?: MetaEntry[]\n pagesMeta?: Record<string, PageMeta>\n} = {}) => {\n const location = useLocation()\n\n useEffect(() => {\n const loadMeta = async () => {\n\n let pageMeta = pagesMeta[location.pathname]\n\n if (!pageMeta) {\n pageMeta = { title: defaultTitle, meta: defaultMeta }\n }\n\n document.title = pageMeta.title\n\n // Remove previous dynamically inserted tags\n document.querySelectorAll(\"[data-react-meta]\").forEach((tag) => tag.remove())\n\n // Inject new tags\n pageMeta.meta.forEach((meta) => {\n const metaElement = document.createElement(\"meta\")\n metaElement.setAttribute(\"data-react-meta\", \"true\")\n\n // Set all attributes from the meta object\n Object.entries(meta).forEach(([key, value]) => {\n if (value) {\n metaElement.setAttribute(key, value.toString())\n }\n })\n\n document.head.appendChild(metaElement)\n })\n\n // Update canonical link\n const canonicalUrl = `${window.location.origin}${location.pathname}`\n\n const existingCanonical = document.querySelector(\"link[rel=\\\"canonical\\\"]\")\n if (existingCanonical) {\n existingCanonical.remove()\n }\n\n const canonicalLink = document.createElement(\"link\")\n canonicalLink.setAttribute(\"rel\", \"canonical\")\n canonicalLink.setAttribute(\"href\", canonicalUrl)\n canonicalLink.setAttribute(\"data-react-meta\", \"true\")\n document.head.appendChild(canonicalLink)\n }\n\n loadMeta()\n }, [location.pathname, defaultTitle, defaultMeta, pagesMeta])\n}\n","import { useEffect, useRef } from \"react\"\nimport type { BlockerFunction } from \"react-router\"\n\n\nexport type NavigationGuard = {\n id: string\n enabled: boolean\n priority?: number\n message: string\n blockOnSearch?: boolean\n shouldBlockNavigation: BlockerFunction\n shouldBlockUnload: boolean\n}\n\ntype NavigationGuardsListener = () => void\n\
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/loadRoute.tsx","../src/useApplyMeta.tsx","../src/navigationGuards.ts"],"sourcesContent":["import { lazy } from \"react\"\nimport { LoaderFunction } from \"react-router\"\nimport { Loader, LoaderArgs } from \"@rpcbase/client\"\n\n\ntype RouteModule = {\n default: React.ComponentType<unknown>\n loader?: Loader\n}\n\ntype RouteWithLoader = {\n Component: React.LazyExoticComponent<React.ComponentType<unknown>>\n loader?: LoaderFunction\n}\n\nexport const loadRoute = (importPromise: Promise<RouteModule>): RouteWithLoader => {\n const Component = lazy(async () => {\n const module = await importPromise\n return { default: module.default }\n })\n\n const loader = async (args: LoaderArgs) => {\n const module = await importPromise\n if (!module.loader) return null\n return module.loader(args)\n }\n\n return { Component, loader: loader as unknown as LoaderFunction }\n}\n","import { useEffect } from \"react\"\nimport { useLocation } from \"react-router\"\n\n\ntype MetaAttributeValue = string | number | boolean | undefined\ntype MetaEntry = Record<string, MetaAttributeValue>\n\ntype PageMeta = {\n title: string\n meta: MetaEntry[]\n}\n\n\nexport const useApplyMeta = ({\n defaultTitle = \"\",\n defaultMeta = [],\n pagesMeta = {}\n}: {\n defaultTitle?: string\n defaultMeta?: MetaEntry[]\n pagesMeta?: Record<string, PageMeta>\n} = {}) => {\n const location = useLocation()\n\n useEffect(() => {\n const loadMeta = async () => {\n\n let pageMeta = pagesMeta[location.pathname]\n\n if (!pageMeta) {\n pageMeta = { title: defaultTitle, meta: defaultMeta }\n }\n\n document.title = pageMeta.title\n\n // Remove previous dynamically inserted tags\n document.querySelectorAll(\"[data-react-meta]\").forEach((tag) => tag.remove())\n\n // Inject new tags\n pageMeta.meta.forEach((meta) => {\n const metaElement = document.createElement(\"meta\")\n metaElement.setAttribute(\"data-react-meta\", \"true\")\n\n // Set all attributes from the meta object\n Object.entries(meta).forEach(([key, value]) => {\n if (value) {\n metaElement.setAttribute(key, value.toString())\n }\n })\n\n document.head.appendChild(metaElement)\n })\n\n // Update canonical link\n const canonicalUrl = `${window.location.origin}${location.pathname}`\n\n const existingCanonical = document.querySelector(\"link[rel=\\\"canonical\\\"]\")\n if (existingCanonical) {\n existingCanonical.remove()\n }\n\n const canonicalLink = document.createElement(\"link\")\n canonicalLink.setAttribute(\"rel\", \"canonical\")\n canonicalLink.setAttribute(\"href\", canonicalUrl)\n canonicalLink.setAttribute(\"data-react-meta\", \"true\")\n document.head.appendChild(canonicalLink)\n }\n\n loadMeta()\n }, [location.pathname, defaultTitle, defaultMeta, pagesMeta])\n}\n","import { useEffect, useRef } from \"react\"\nimport type { BlockerFunction } from \"react-router\"\n\n\nexport type NavigationGuard = {\n id: string\n enabled: boolean\n priority?: number\n message: string\n blockOnSearch?: boolean\n shouldBlockNavigation: BlockerFunction\n shouldBlockUnload: boolean\n}\n\ntype NavigationGuardsListener = () => void\n\ntype NavigationGuardsStore = {\n guards: Map<string, NavigationGuard>\n listeners: Set<NavigationGuardsListener>\n}\n\nconst NAVIGATION_GUARDS_STORE_KEY = \"__rpcbaseNavigationGuardsStore\"\n\nconst getNavigationGuardsStore = (): NavigationGuardsStore => {\n const globalAny = globalThis as {\n [NAVIGATION_GUARDS_STORE_KEY]?: NavigationGuardsStore\n }\n\n const existing = globalAny[NAVIGATION_GUARDS_STORE_KEY]\n if (existing) {\n return existing\n }\n\n const created: NavigationGuardsStore = {\n guards: new Map<string, NavigationGuard>(),\n listeners: new Set<NavigationGuardsListener>(),\n }\n\n globalAny[NAVIGATION_GUARDS_STORE_KEY] = created\n return created\n}\n\nconst notify = (): void => {\n getNavigationGuardsStore().listeners.forEach((listener) => {\n listener()\n })\n}\n\nconst isSameGuard = (a: NavigationGuard, b: NavigationGuard): boolean =>\n a.id === b.id &&\n a.enabled === b.enabled &&\n a.priority === b.priority &&\n a.message === b.message &&\n a.blockOnSearch === b.blockOnSearch &&\n a.shouldBlockNavigation === b.shouldBlockNavigation &&\n a.shouldBlockUnload === b.shouldBlockUnload\n\nexport const upsertNavigationGuard = (guard: NavigationGuard): void => {\n const guards = getNavigationGuardsStore().guards\n const prev = guards.get(guard.id)\n if (prev && isSameGuard(prev, guard)) {\n return\n }\n\n guards.set(guard.id, guard)\n notify()\n}\n\nexport const removeNavigationGuard = (id: string): void => {\n const guards = getNavigationGuardsStore().guards\n const didDelete = guards.delete(id)\n if (didDelete) {\n notify()\n }\n}\n\nexport const getNavigationGuards = (): NavigationGuard[] =>\n Array.from(getNavigationGuardsStore().guards.values())\n\nexport const subscribeNavigationGuards = (\n listener: NavigationGuardsListener,\n): (() => void) => {\n const listeners = getNavigationGuardsStore().listeners\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n}\n\nexport const useRegisterNavigationGuard = (guard: NavigationGuard): void => {\n const latestGuardRef = useRef(guard)\n latestGuardRef.current = guard\n\n const lastIdRef = useRef<string | null>(null)\n\n useEffect(() => {\n const lastId = lastIdRef.current\n if (lastId && lastId !== guard.id) {\n removeNavigationGuard(lastId)\n }\n lastIdRef.current = guard.id\n\n if (!guard.enabled) {\n removeNavigationGuard(guard.id)\n return\n }\n\n upsertNavigationGuard(latestGuardRef.current)\n return () => {\n removeNavigationGuard(guard.id)\n }\n }, [\n guard.id,\n guard.enabled,\n guard.message,\n guard.priority,\n guard.blockOnSearch,\n guard.shouldBlockNavigation,\n guard.shouldBlockUnload,\n ])\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigationGuards.d.ts","sourceRoot":"","sources":["../src/navigationGuards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAGnD,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,qBAAqB,EAAE,eAAe,CAAA;IACtC,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,KAAK,wBAAwB,GAAG,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"navigationGuards.d.ts","sourceRoot":"","sources":["../src/navigationGuards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAGnD,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,qBAAqB,EAAE,eAAe,CAAA;IACtC,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,KAAK,wBAAwB,GAAG,MAAM,IAAI,CAAA;AA2C1C,eAAO,MAAM,qBAAqB,GAAI,OAAO,eAAe,KAAG,IAS9D,CAAA;AAED,eAAO,MAAM,qBAAqB,GAAI,IAAI,MAAM,KAAG,IAMlD,CAAA;AAED,eAAO,MAAM,mBAAmB,QAAO,eAAe,EACE,CAAA;AAExD,eAAO,MAAM,yBAAyB,GACpC,UAAU,wBAAwB,KACjC,CAAC,MAAM,IAAI,CAMb,CAAA;AAED,eAAO,MAAM,0BAA0B,GAAI,OAAO,eAAe,KAAG,IA+BnE,CAAA"}
|