@hitachivantara/app-shell-navigation 1.2.6 → 1.2.8

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.
@@ -0,0 +1,30 @@
1
+ import { useMemo } from "react";
2
+ import { useHvMenuItems } from "@hitachivantara/app-shell-shared";
3
+ const useCurrentNavigationPath = () => {
4
+ const {
5
+ items,
6
+ selectedMenuItemId
7
+ } = useHvMenuItems();
8
+ return useMemo(() => {
9
+ let currentItems = items;
10
+ if (!selectedMenuItemId) {
11
+ return [];
12
+ }
13
+ const paths = [];
14
+ const selectedPathIds = selectedMenuItemId.split("-");
15
+ selectedPathIds.forEach((item) => {
16
+ const currentItem = currentItems[parseInt(item, 10)];
17
+ paths.push({
18
+ label: currentItem.label,
19
+ path: currentItem.data ? void 0 : currentItem.href
20
+ });
21
+ if (currentItem.data) {
22
+ currentItems = currentItem.data;
23
+ }
24
+ });
25
+ return paths;
26
+ }, [items, selectedMenuItemId]);
27
+ };
28
+ export {
29
+ useCurrentNavigationPath
30
+ };
@@ -0,0 +1,55 @@
1
+ import { useMemo } from "react";
2
+ import { useLocation as useLocation$1, matchRoutes } from "react-router-dom";
3
+ import { useHvAppShellConfig } from "@hitachivantara/app-shell-shared";
4
+ function indexViews(views) {
5
+ return views.map((view) => {
6
+ const path = view.route.slice(1);
7
+ const isIndex = path === "" && (view.views == null || view.views.length === 0);
8
+ if (isIndex) {
9
+ return {
10
+ path,
11
+ view
12
+ };
13
+ }
14
+ return {
15
+ path,
16
+ view,
17
+ children: view.views ? indexViews(view.views) : void 0
18
+ };
19
+ });
20
+ }
21
+ class LocationWithViews {
22
+ state;
23
+ key;
24
+ pathname;
25
+ search;
26
+ hash;
27
+ #configViews;
28
+ matches = null;
29
+ constructor(location, views) {
30
+ this.state = location.state;
31
+ this.key = location.key;
32
+ this.pathname = location.pathname;
33
+ this.search = location.search;
34
+ this.hash = location.hash;
35
+ this.#configViews = views ?? [];
36
+ }
37
+ get views() {
38
+ if (this.matches == null) {
39
+ const indexedViews = indexViews(this.#configViews);
40
+ this.matches = matchRoutes(indexedViews, this)?.map((match) => match.route.view) ?? [];
41
+ }
42
+ return this.matches;
43
+ }
44
+ }
45
+ const useLocation = () => {
46
+ const location = useLocation$1();
47
+ const config = useHvAppShellConfig();
48
+ const toReturn = useMemo(() => {
49
+ return new LocationWithViews(location, config.mainPanel?.views);
50
+ }, [location, config.mainPanel?.views]);
51
+ return toReturn;
52
+ };
53
+ export {
54
+ useLocation
55
+ };
@@ -0,0 +1,137 @@
1
+ import { useMemo, useContext, useRef, useCallback } from "react";
2
+ import { useNavigate } from "react-router-dom";
3
+ import { useHvAppShellConfig, HvAppShellViewContext } from "@hitachivantara/app-shell-shared";
4
+ import compileHref from "../utils/navigationUtil.js";
5
+ import { useLocation } from "./useLocation.js";
6
+ const isViewDestination = (to) => {
7
+ return to.viewBundle !== void 0;
8
+ };
9
+ const isPathDestination = (to) => {
10
+ return typeof to !== "string" && !isViewDestination(to);
11
+ };
12
+ function getActiveViewRoute(activeViews, depth) {
13
+ return `/${activeViews.map((view) => view.route.substring(1)).slice(0, depth ?? activeViews.length).filter((route) => route !== "").join("/")}`;
14
+ }
15
+ function isSameBundle(v, bundle, appId) {
16
+ return v.bundle === `${bundle}` || v.bundle === `${bundle}.js` || v.bundle === `${appId}/${bundle}.js` || v.bundle === `${appId}/${bundle}`;
17
+ }
18
+ const useNavigation = () => {
19
+ const config = useHvAppShellConfig();
20
+ const flattenViews = useMemo(() => {
21
+ const flatten = (views, base = "") => {
22
+ return views.reduce((acc, view) => {
23
+ const route = `${base}${view.route}`;
24
+ acc.push({
25
+ ...view,
26
+ route
27
+ });
28
+ if (view.views != null) {
29
+ acc.push(...flatten(view.views, route));
30
+ }
31
+ return acc;
32
+ }, []);
33
+ };
34
+ return flatten(config.mainPanel?.views ?? []);
35
+ }, [config.mainPanel?.views]);
36
+ const viewContext = useContext(HvAppShellViewContext);
37
+ const navigateReactRouter = useNavigate();
38
+ const location = useLocation();
39
+ const locationRef = useRef(location);
40
+ locationRef.current = location;
41
+ const getViewRoute = useCallback((viewBundleDir, {
42
+ mode = "auto"
43
+ } = {}) => {
44
+ let viewBundle;
45
+ let pathParams;
46
+ let search;
47
+ let hash;
48
+ if (isViewDestination(viewBundleDir)) {
49
+ ({
50
+ viewBundle,
51
+ pathParams,
52
+ search,
53
+ hash
54
+ } = viewBundleDir);
55
+ } else {
56
+ viewBundle = viewBundleDir;
57
+ }
58
+ const bundleWithReplacedPlaceholders = viewBundle.replace(/\$/, "_");
59
+ let appId;
60
+ let bundle;
61
+ if (bundleWithReplacedPlaceholders.startsWith("/")) {
62
+ appId = viewContext?.id;
63
+ bundle = bundleWithReplacedPlaceholders.substring(1);
64
+ } else {
65
+ bundle = bundleWithReplacedPlaceholders;
66
+ }
67
+ let activeViews = [];
68
+ if (mode !== "top") {
69
+ activeViews = locationRef.current.views;
70
+ }
71
+ let route;
72
+ const matchingViews = flattenViews.filter((v) => isSameBundle(v, bundle, appId)).sort((a, b) => {
73
+ const aSlashCount = (a.route.match(/\//g) ?? []).length;
74
+ const bSlashCount = (b.route.match(/\//g) ?? []).length;
75
+ return aSlashCount - bSlashCount;
76
+ });
77
+ if (matchingViews.length > 0) {
78
+ if (mode === "top" || matchingViews.length === 1) {
79
+ route = matchingViews[0].route;
80
+ } else if (mode === "auto") {
81
+ const activeViewRoute = getActiveViewRoute(activeViews);
82
+ let path = `${activeViewRoute}/`;
83
+ while (route == null) {
84
+ const innerPath = path;
85
+ route = matchingViews.find((v) => v.route.startsWith(innerPath))?.route;
86
+ path = path.replace(/\/[^/]*\/?$/, "/");
87
+ if (path === "") {
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ }
93
+ return route ? `${compileHref(route, pathParams)}${search ?? ""}${hash ?? ""}` : void 0;
94
+ }, [flattenViews, viewContext?.id]);
95
+ const navigate = useCallback((to, options) => {
96
+ let path;
97
+ if (isPathDestination(to)) {
98
+ path = to;
99
+ } else {
100
+ const route = getViewRoute(to, {
101
+ mode: options?.mode
102
+ });
103
+ if (route == null) {
104
+ if (typeof to === "string") {
105
+ path = to;
106
+ } else {
107
+ console.warn(`Navigate request to a non existing path [${to.viewBundle}]. Skipping`);
108
+ return;
109
+ }
110
+ } else {
111
+ path = route;
112
+ }
113
+ }
114
+ let navigateOptions;
115
+ if (options != null) {
116
+ if (options.mode == null) {
117
+ navigateOptions = options;
118
+ } else {
119
+ navigateOptions = {
120
+ ...options
121
+ };
122
+ delete navigateOptions.mode;
123
+ if (Object.keys(navigateOptions).length === 0) {
124
+ navigateOptions = void 0;
125
+ }
126
+ }
127
+ }
128
+ navigateReactRouter(path, navigateOptions);
129
+ }, [getViewRoute, navigateReactRouter]);
130
+ return {
131
+ getViewRoute,
132
+ navigate
133
+ };
134
+ };
135
+ export {
136
+ useNavigation
137
+ };
package/dist/esm/index.js CHANGED
@@ -1,9 +1,8 @@
1
- import { default as e } from "./lib/hooks/useNavigation.js";
2
- import { default as r } from "./lib/hooks/useCurrentNavigationPath.js";
3
- import { default as f } from "./lib/hooks/useLocation.js";
1
+ import { useCurrentNavigationPath } from "./hooks/useCurrentNavigationPath.js";
2
+ import { useNavigation } from "./hooks/useNavigation.js";
3
+ import { useLocation } from "./hooks/useLocation.js";
4
4
  export {
5
- r as useHvCurrentNavigationPath,
6
- f as useHvLocation,
7
- e as useHvNavigation
5
+ useCurrentNavigationPath as useHvCurrentNavigationPath,
6
+ useLocation as useHvLocation,
7
+ useNavigation as useHvNavigation
8
8
  };
9
- //# sourceMappingURL=index.js.map
@@ -0,0 +1,11 @@
1
+ import { compile } from "path-to-regexp";
2
+ const compileHref = (href, hrefOptions) => {
3
+ if (!hrefOptions) {
4
+ return href;
5
+ }
6
+ const compiler = compile(href);
7
+ return compiler(hrefOptions);
8
+ };
9
+ export {
10
+ compileHref as default
11
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hitachivantara/app-shell-navigation",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "AppShell Navigation",
5
5
  "author": "Hitachi Vantara - Boba Fett Team",
6
6
  "license": "Apache-2.0",
@@ -35,8 +35,8 @@
35
35
  "coverage": "vitest run --coverage"
36
36
  },
37
37
  "dependencies": {
38
- "@hitachivantara/app-shell-shared": "1.4.0",
39
- "path-to-regexp": "^6.2.1"
38
+ "@hitachivantara/app-shell-shared": "1.4.2",
39
+ "path-to-regexp": "^8.1.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "react": "^18.2.0",
@@ -51,10 +51,7 @@
51
51
  "react-error-boundary": "^4.0.10",
52
52
  "react-i18next": "^13.5.0",
53
53
  "rimraf": "^5.0.5",
54
- "typescript": "^5.3.2",
55
- "vite": "^5.0.4",
56
- "vite-plugin-dts": "^3.6.4",
57
- "vite-tsconfig-paths": "^4.0.5"
54
+ "vite": "^5.0.4"
58
55
  },
59
- "gitHead": "a5e510ddd0eb8aeed19ea2bf8005918bb7e3b04f"
56
+ "gitHead": "863f86de4fc34efe9b5f129fe08f676af51c9e1b"
60
57
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -1,25 +0,0 @@
1
- import { useMemo as o } from "react";
2
- import { useHvMenuItems as u } from "@hitachivantara/app-shell-shared";
3
- const c = () => {
4
- const {
5
- items: s,
6
- selectedMenuItemId: e
7
- } = u();
8
- return o(() => {
9
- let a = s;
10
- if (!e)
11
- return [];
12
- const r = [];
13
- return e.split("-").forEach((n) => {
14
- const t = a[parseInt(n, 10)];
15
- r.push({
16
- label: t.label,
17
- path: t.data ? void 0 : t.href
18
- }), t.data && (a = t.data);
19
- }), r;
20
- }, [s, e]);
21
- }, m = c;
22
- export {
23
- m as default
24
- };
25
- //# sourceMappingURL=useCurrentNavigationPath.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useCurrentNavigationPath.js","sources":["../../../../src/lib/hooks/useCurrentNavigationPath.tsx"],"sourcesContent":["import { useMemo } from \"react\";\r\nimport { useHvMenuItems } from \"@hitachivantara/app-shell-shared\";\r\n\r\nconst useCurrentNavigationPath = () => {\r\n const { items, selectedMenuItemId } = useHvMenuItems();\r\n return useMemo(() => {\r\n let currentItems = items;\r\n\r\n if (!selectedMenuItemId) {\r\n return [];\r\n }\r\n const paths: { label: string; path: string | undefined }[] = [];\r\n\r\n const selectedPathIds = selectedMenuItemId.split(\"-\");\r\n selectedPathIds.forEach(item => {\r\n const currentItem = currentItems[parseInt(item, 10)];\r\n paths.push({\r\n label: currentItem.label,\r\n path: currentItem.data ? undefined : currentItem.href\r\n });\r\n if (currentItem.data) {\r\n currentItems = currentItem.data;\r\n }\r\n });\r\n\r\n return paths;\r\n }, [items, selectedMenuItemId]);\r\n};\r\n\r\nexport default useCurrentNavigationPath;\r\n"],"names":["useCurrentNavigationPath","items","selectedMenuItemId","useHvMenuItems","useMemo","currentItems","paths","selectedPathIds","split","forEach","item","currentItem","parseInt","push","label","path","data","undefined","href","useCurrentNavigationPath$1"],"mappings":";;AAGA,MAAMA,IAA2BA,MAAM;AAC/B,QAAA;AAAA,IAAEC,OAAAA;AAAAA,IAAOC,oBAAAA;AAAAA,MAAuBC,EAAe;AACrD,SAAOC,EAAQ,MAAM;AACnB,QAAIC,IAAeJ;AAEnB,QAAI,CAACC;AACH,aAAO;AAET,UAAMI,IAAuD,CAAA;AAG7DC,WADwBL,EAAmBM,MAAM,GAAG,EACpCC,QAAQC,CAAQA,MAAA;AAC9B,YAAMC,IAAcN,EAAaO,SAASF,GAAM,EAAE,CAAC;AACnDJ,MAAAA,EAAMO,KAAK;AAAA,QACTC,OAAOH,EAAYG;AAAAA,QACnBC,MAAMJ,EAAYK,OAAOC,SAAYN,EAAYO;AAAAA,MAAAA,CAClD,GACGP,EAAYK,SACdX,IAAeM,EAAYK;AAAAA,IAC7B,CACD,GAEMV;AAAAA,EAAAA,GACN,CAACL,GAAOC,CAAkB,CAAC;AAChC,GAEAiB,IAAenB;"}
@@ -1,57 +0,0 @@
1
- var p = Object.defineProperty;
2
- var o = (s) => {
3
- throw TypeError(s);
4
- };
5
- var f = (s, t, e) => t in s ? p(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
6
- var i = (s, t, e) => f(s, typeof t != "symbol" ? t + "" : t, e), r = (s, t, e) => t.has(s) || o("Cannot " + e);
7
- var c = (s, t, e) => (r(s, t, "read from private field"), e ? e.call(s) : t.get(s)), u = (s, t, e) => t.has(s) ? o("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(s) : t.set(s, e), m = (s, t, e, n) => (r(s, t, "write to private field"), n ? n.call(s, e) : t.set(s, e), e);
8
- import { useMemo as d } from "react";
9
- import { useLocation as w, matchRoutes as g } from "react-router-dom";
10
- import { useHvAppShellConfig as v } from "@hitachivantara/app-shell-shared";
11
- function l(s) {
12
- return s.map((t) => {
13
- const e = t.route.slice(1);
14
- return e === "" && (t.views == null || t.views.length === 0) ? {
15
- path: e,
16
- view: t
17
- } : {
18
- path: e,
19
- view: t,
20
- children: t.views ? l(t.views) : void 0
21
- };
22
- });
23
- }
24
- var a;
25
- class x {
26
- constructor(t, e) {
27
- i(this, "state");
28
- i(this, "key");
29
- i(this, "pathname");
30
- i(this, "search");
31
- i(this, "hash");
32
- u(this, a);
33
- i(this, "matches", null);
34
- this.state = t.state, this.key = t.key, this.pathname = t.pathname, this.search = t.search, this.hash = t.hash, m(this, a, e ?? []);
35
- }
36
- get views() {
37
- var t;
38
- if (this.matches == null) {
39
- const e = l(c(this, a));
40
- this.matches = ((t = g(e, this)) == null ? void 0 : t.map((n) => n.route.view)) ?? [];
41
- }
42
- return this.matches;
43
- }
44
- }
45
- a = new WeakMap();
46
- const L = () => {
47
- var n;
48
- const s = w(), t = v();
49
- return d(() => {
50
- var h;
51
- return new x(s, (h = t.mainPanel) == null ? void 0 : h.views);
52
- }, [s, (n = t.mainPanel) == null ? void 0 : n.views]);
53
- }, H = L;
54
- export {
55
- H as default
56
- };
57
- //# sourceMappingURL=useLocation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useLocation.js","sources":["../../../../src/lib/hooks/useLocation.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport {\n matchRoutes,\n useLocation as useLocationReactRouter,\n Location\n} from \"react-router-dom\";\n\nimport {\n HvAppShellViewsConfig,\n useHvAppShellConfig\n} from \"@hitachivantara/app-shell-shared\";\n\ninterface IndexedView {\n path: string;\n children?: IndexedView[];\n view: HvAppShellViewsConfig;\n}\n\nfunction indexViews(views: HvAppShellViewsConfig[]): IndexedView[] {\n return views.map(view => {\n // remove prefix slash from view.route\n const path = view.route.slice(1);\n const isIndex =\n path === \"\" && (view.views == null || view.views.length === 0);\n\n if (isIndex) {\n return {\n path,\n view\n };\n }\n\n return {\n path,\n view,\n children: view.views ? indexViews(view.views) : undefined\n };\n });\n}\n\nclass LocationWithViews<State = unknown> implements Location<State> {\n state: State;\n\n key: string;\n\n pathname: string;\n\n search: string;\n\n hash: string;\n\n #configViews: HvAppShellViewsConfig[];\n\n private matches: HvAppShellViewsConfig[] | null = null;\n\n constructor(\n location: Location<State>,\n views: HvAppShellViewsConfig[] | undefined | null\n ) {\n this.state = location.state;\n this.key = location.key;\n this.pathname = location.pathname;\n this.search = location.search;\n this.hash = location.hash;\n\n this.#configViews = views ?? [];\n }\n\n get views() {\n if (this.matches == null) {\n const indexedViews = indexViews(this.#configViews);\n this.matches =\n matchRoutes(indexedViews, this)?.map(match => match.route.view) ?? [];\n }\n\n return this.matches;\n }\n}\n\nconst useLocation = () => {\n const location = useLocationReactRouter();\n const config = useHvAppShellConfig();\n const toReturn = useMemo(() => {\n return new LocationWithViews(location, config.mainPanel?.views);\n }, [location, config.mainPanel?.views]);\n\n return toReturn;\n};\nexport default useLocation;\n"],"names":["indexViews","views","map","view","path","route","slice","length","children","undefined","LocationWithViews","constructor","location","state","key","pathname","search","hash","__privateAdd","_configViews","matches","__privateSet","indexedViews","__privateGet","matchRoutes","match","useLocation","useLocationReactRouter","config","useHvAppShellConfig","toReturn","useMemo","mainPanel","useHvLocation"],"mappings":";;;;;;;;;;AAkBA,SAASA,EAAWC,GAA+C;AAC1DA,SAAAA,EAAMC,IAAIC,CAAQA,MAAA;AAEvB,UAAMC,IAAOD,EAAKE,MAAMC,MAAM,CAAC;AAI/B,WAFEF,MAAS,OAAOD,EAAKF,SAAS,QAAQE,EAAKF,MAAMM,WAAW,KAGrD;AAAA,MACLH,MAAAA;AAAAA,MACAD,MAAAA;AAAAA,IAAAA,IAIG;AAAA,MACLC,MAAAA;AAAAA,MACAD,MAAAA;AAAAA,MACAK,UAAUL,EAAKF,QAAQD,EAAWG,EAAKF,KAAK,IAAIQ;AAAAA,IAAAA;AAAAA,EAClD,CACD;AACH;;AAEA,MAAMC,EAA8D;AAAA,EAelEC,YACEC,GACAX,GACA;AAjBFY,IAAAA,EAAAA;AAEAC,IAAAA,EAAAA;AAEAC,IAAAA,EAAAA;AAEAC,IAAAA,EAAAA;AAEAC,IAAAA,EAAAA;AAEA,IAAAC,EAAA,MAAAC;AAEQC,IAAAA,EAAAA,iBAA0C;AAMhD,SAAKP,QAAQD,EAASC,OACtB,KAAKC,MAAMF,EAASE,KACpB,KAAKC,WAAWH,EAASG,UACzB,KAAKC,SAASJ,EAASI,QACvB,KAAKC,OAAOL,EAASK,MAEhBI,EAAA,MAAAF,GAAelB,KAAS;EAC/B;AAAA,EAEA,IAAIA,QAAQ;;AACN,QAAA,KAAKmB,WAAW,MAAM;AAClBE,YAAAA,IAAetB,EAAWuB,EAAA,MAAKJ,EAAY;AAC5CC,WAAAA,YACHI,IAAAA,EAAYF,GAAc,IAAI,MAA9BE,gBAAAA,EAAiCtB,IAAIuB,CAAAA,MAASA,EAAMpB,MAAMF,UAAS,CAAA;AAAA,IACvE;AAEA,WAAO,KAAKiB;AAAAA,EACd;AACF;AA1BED,IAAA;AA4BF,MAAMO,IAAcA,MAAM;;AACxB,QAAMd,IAAWe,KACXC,IAASC;AAKRC,SAJUC,EAAQ,MAAM;;AAC7B,WAAO,IAAIrB,EAAkBE,IAAUgB,IAAAA,EAAOI,cAAPJ,gBAAAA,EAAkB3B,KAAK;AAAA,KAC7D,CAACW,IAAUgB,IAAAA,EAAOI,cAAPJ,gBAAAA,EAAkB3B,KAAK,CAAC;AAGxC,GACAgC,IAAeP;"}
@@ -1,92 +0,0 @@
1
- import { useMemo as N, useContext as y, useRef as A, useCallback as j } from "react";
2
- import { useNavigate as C } from "react-router-dom";
3
- import { useHvAppShellConfig as W, HvAppShellViewContext as B } from "@hitachivantara/app-shell-shared";
4
- import O from "../utils/navigationUtil.js";
5
- import q from "./useLocation.js";
6
- const k = (e) => e.viewBundle !== void 0, x = (e) => typeof e != "string" && !k(e);
7
- function L(e, r) {
8
- return `/${e.map((n) => n.route.substring(1)).slice(0, r ?? e.length).filter((n) => n !== "").join("/")}`;
9
- }
10
- function M(e, r, n) {
11
- return e.bundle === `${r}` || e.bundle === `${r}.js` || e.bundle === `${n}/${r}.js` || e.bundle === `${n}/${r}`;
12
- }
13
- const _ = () => {
14
- var R;
15
- const e = W(), r = N(() => {
16
- var t;
17
- const i = (l, s = "") => l.reduce((o, u) => {
18
- const a = `${s}${u.route}`;
19
- return o.push({
20
- ...u,
21
- route: a
22
- }), u.views != null && o.push(...i(u.views, a)), o;
23
- }, []);
24
- return i(((t = e.mainPanel) == null ? void 0 : t.views) ?? []);
25
- }, [(R = e.mainPanel) == null ? void 0 : R.views]), n = y(B), v = C(), w = q(), b = A(w);
26
- b.current = w;
27
- const m = j((i, {
28
- mode: t = "auto"
29
- } = {}) => {
30
- var S;
31
- let l, s, o, u;
32
- k(i) ? {
33
- viewBundle: l,
34
- pathParams: s,
35
- search: o,
36
- hash: u
37
- } = i : l = i;
38
- const a = l.replace(/\$/, "_");
39
- let V, p;
40
- a.startsWith("/") ? (V = n == null ? void 0 : n.id, p = a.substring(1)) : p = a;
41
- let P = [];
42
- t !== "top" && (P = b.current.views);
43
- let f;
44
- const h = r.filter((g) => M(g, p, V)).sort((g, c) => {
45
- const d = (g.route.match(/\//g) ?? []).length, $ = (c.route.match(/\//g) ?? []).length;
46
- return d - $;
47
- });
48
- if (h.length > 0) {
49
- if (t === "top" || h.length === 1)
50
- f = h[0].route;
51
- else if (t === "auto") {
52
- let c = `${L(P)}/`;
53
- for (; f == null; ) {
54
- const d = c;
55
- if (f = (S = h.find(($) => $.route.startsWith(d))) == null ? void 0 : S.route, c = c.replace(/\/[^/]*\/?$/, "/"), c === "")
56
- break;
57
- }
58
- }
59
- }
60
- return f ? `${O(f, s)}${o ?? ""}${u ?? ""}` : void 0;
61
- }, [r, n == null ? void 0 : n.id]), H = j((i, t) => {
62
- let l;
63
- if (x(i))
64
- l = i;
65
- else {
66
- const o = m(i, {
67
- mode: t == null ? void 0 : t.mode
68
- });
69
- if (o == null)
70
- if (typeof i == "string")
71
- l = i;
72
- else {
73
- console.warn(`Navigate request to a non existing path [${i.viewBundle}]. Skipping`);
74
- return;
75
- }
76
- else
77
- l = o;
78
- }
79
- let s;
80
- t != null && (t.mode == null ? s = t : (s = {
81
- ...t
82
- }, delete s.mode, Object.keys(s).length === 0 && (s = void 0))), v(l, s);
83
- }, [m, v]);
84
- return {
85
- getViewRoute: m,
86
- navigate: H
87
- };
88
- }, I = _;
89
- export {
90
- I as default
91
- };
92
- //# sourceMappingURL=useNavigation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useNavigation.js","sources":["../../../../src/lib/hooks/useNavigation.tsx"],"sourcesContent":["import { useCallback, useContext, useMemo, useRef } from \"react\";\nimport { Path, useNavigate } from \"react-router-dom\";\n\nimport {\n HvAppShellViewContext,\n HvAppShellViewsConfig,\n useHvAppShellConfig\n} from \"@hitachivantara/app-shell-shared\";\n\nimport { NavigationOptions, To, ViewDestination } from \"../types\";\nimport compileHref from \"../utils/navigationUtil\";\nimport useHvLocation from \"./useLocation\";\n\nconst isViewDestination = (to: To): to is ViewDestination => {\n return (to as ViewDestination).viewBundle !== undefined;\n};\n\nconst isPathDestination = (to: To): to is Partial<Path> => {\n return typeof to !== \"string\" && !isViewDestination(to);\n};\n\ntype ViewSearchMode = \"auto\" | \"top\";\n\ninterface GetViewRouteOptions {\n mode?: ViewSearchMode;\n}\n\ntype NavigateOptions = GetViewRouteOptions & Partial<NavigationOptions>;\n\nfunction getActiveViewRoute(\n activeViews: HvAppShellViewsConfig[],\n depth?: number\n): string {\n return `/${activeViews\n .map(view => view.route.substring(1))\n .slice(0, depth ?? activeViews.length)\n .filter(route => route !== \"\") // remove index routes\n .join(\"/\")}`;\n}\n\nfunction isSameBundle(\n v: HvAppShellViewsConfig,\n bundle: string,\n appId: string | undefined\n) {\n return (\n v.bundle === `${bundle}` ||\n v.bundle === `${bundle}.js` ||\n v.bundle === `${appId}/${bundle}.js` ||\n v.bundle === `${appId}/${bundle}`\n );\n}\n\nconst useNavigation = () => {\n const config = useHvAppShellConfig();\n const flattenViews = useMemo(() => {\n const flatten = (views: HvAppShellViewsConfig[], base = \"\") => {\n return views.reduce<HvAppShellViewsConfig[]>((acc, view) => {\n // concatenate base with view route\n const route = `${base}${view.route}` as HvAppShellViewsConfig[\"route\"];\n acc.push({ ...view, route });\n if (view.views != null) {\n acc.push(...flatten(view.views, route));\n }\n return acc;\n }, []);\n };\n return flatten(config.mainPanel?.views ?? []);\n }, [config.mainPanel?.views]);\n\n const viewContext = useContext(HvAppShellViewContext);\n const navigateReactRouter = useNavigate();\n\n // the returned navigate and getViewRoute functions need to be stable\n // regardless of the location change, but we need to use the most recent location\n // in the getViewRoute algorithm, so we use a ref to store the location\n const location = useHvLocation();\n const locationRef = useRef(location);\n locationRef.current = location;\n\n /**\n * Utility to search for the route of a View on the App Shell configuration.\n *\n * The search can be performed in different modes:\n * - \"auto\": Searches within views whose route is a subpath of the current active view, progressively going up path segments until a match is found.\n * - \"top\": Finds the view closest to the root, i.e. with the least number of path segments.\n *\n * If multiple views match the search criteria, the function returns the one that appears first in the App Shell configuration.\n *\n * @param viewBundleDir The application view bundle directory name and optional route parameters.\n * @param mode The search mode to use. Defaults to \"auto\".\n *\n * @returns The compiled route or undefined if none was found.\n */\n const getViewRoute = useCallback(\n (\n viewBundleDir: string | ViewDestination,\n { mode = \"auto\" }: GetViewRouteOptions = {}\n ): string | undefined => {\n let viewBundle;\n let pathParams;\n let search;\n let hash;\n\n if (isViewDestination(viewBundleDir)) {\n ({ viewBundle, pathParams, search, hash } = viewBundleDir);\n } else {\n viewBundle = viewBundleDir;\n }\n const bundleWithReplacedPlaceholders = viewBundle.replace(/\\$/, \"_\");\n\n let appId: string | undefined;\n let bundle: string;\n\n // local navigation\n if (bundleWithReplacedPlaceholders.startsWith(\"/\")) {\n appId = viewContext?.id;\n bundle = bundleWithReplacedPlaceholders.substring(1);\n } else {\n bundle = bundleWithReplacedPlaceholders;\n }\n\n let activeViews: HvAppShellViewsConfig[] = [];\n if (mode !== \"top\") {\n activeViews = locationRef.current.views;\n }\n\n let route: string | undefined;\n\n const matchingViews = flattenViews\n .filter(v => isSameBundle(v, bundle, appId))\n .sort((a, b) => {\n const aSlashCount = (a.route.match(/\\//g) ?? []).length;\n const bSlashCount = (b.route.match(/\\//g) ?? []).length;\n return aSlashCount - bSlashCount;\n });\n\n if (matchingViews.length > 0) {\n if (mode === \"top\" || matchingViews.length === 1) {\n // no need for search algorithms if there is only one matching view\n route = matchingViews[0].route;\n } else if (mode === \"auto\") {\n const activeViewRoute = getActiveViewRoute(activeViews);\n\n let path = `${activeViewRoute}/`;\n while (route == null) {\n const innerPath = path;\n route = matchingViews.find(v =>\n v.route.startsWith(innerPath)\n )?.route;\n\n // remove last path segment, e.g. /path/segment/ -> /path/ -> /\n path = path.replace(/\\/[^/]*\\/?$/, \"/\");\n\n if (path === \"\") {\n break;\n }\n }\n }\n }\n\n return route\n ? `${compileHref(route, pathParams)}${search ?? \"\"}${hash ?? \"\"}`\n : undefined;\n },\n [flattenViews, viewContext?.id]\n );\n\n /**\n * Performs navigation, through 'history.push' or 'history.replace', for the given destination with the passed navigation options.\n * @see https://reactrouter.com/hooks/use-navigate\n *\n * @param to The destination of the navigation. For ViewDestination type see {@link ViewDestination}.\n * @param options The navigation options:\n * - mode: The search mode to use when searching for the route of a View on the App Shell configuration. Defaults to \"auto\".\n * - replace: If true, the navigation will replace the current entry in the history stack instead of adding a new one.\n * - state: State to associate to the location.\n */\n const navigate = useCallback(\n (to: To, options?: NavigateOptions) => {\n let path;\n if (isPathDestination(to)) {\n path = to;\n } else {\n const route = getViewRoute(to, { mode: options?.mode });\n\n if (route == null) {\n if (typeof to === \"string\") {\n path = to;\n } else {\n // If route for given module is not found on the App Shell configuration file, do nothing.\n console.warn(\n `Navigate request to a non existing path [${to.viewBundle}]. Skipping`\n );\n return;\n }\n } else {\n path = route;\n }\n }\n\n let navigateOptions: NavigateOptions | undefined;\n if (options != null) {\n if (options.mode == null) {\n navigateOptions = options;\n } else {\n navigateOptions = { ...options };\n delete navigateOptions.mode;\n if (Object.keys(navigateOptions).length === 0) {\n navigateOptions = undefined;\n }\n }\n }\n\n navigateReactRouter(path, navigateOptions);\n },\n [getViewRoute, navigateReactRouter]\n );\n\n return { getViewRoute, navigate };\n};\n\nexport default useNavigation;\n"],"names":["isViewDestination","to","viewBundle","undefined","isPathDestination","getActiveViewRoute","activeViews","depth","map","view","route","substring","slice","length","filter","join","isSameBundle","v","bundle","appId","useNavigation","config","useHvAppShellConfig","flattenViews","useMemo","flatten","views","base","reduce","acc","push","mainPanel","viewContext","useContext","HvAppShellViewContext","navigateReactRouter","useNavigate","location","useHvLocation","locationRef","useRef","current","getViewRoute","useCallback","viewBundleDir","mode","pathParams","search","hash","bundleWithReplacedPlaceholders","replace","startsWith","id","matchingViews","sort","a","b","aSlashCount","match","bSlashCount","path","innerPath","find","compileHref","navigate","options","console","warn","navigateOptions","Object","keys","useNavigation$1"],"mappings":"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"}
@@ -1,9 +0,0 @@
1
- import { compile as c } from "path-to-regexp";
2
- const l = (e, o) => o ? c(e, {
3
- encode: encodeURIComponent,
4
- validate: !1
5
- })(o) : e;
6
- export {
7
- l as default
8
- };
9
- //# sourceMappingURL=navigationUtil.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"navigationUtil.js","sources":["../../../../src/lib/utils/navigationUtil.tsx"],"sourcesContent":["import { compile } from \"path-to-regexp\";\n\n/**\n * Utility that replaces the href placeholders with the href options provided.\n * The href parameter must not contain 'search' nor 'hash' parts.\n * @example\n * // returns '/home/2'\n * // href: '/home/:id', hrefOptions: '{id: 2}'\n *\n * @param href The string to be compiled.\n * @param hrefOptions The options to replace the placeholders on the href.\n *\n * @returns The compiled href\n */\nconst compileHref = (\n href: string,\n hrefOptions?: Record<string, string>\n): string => {\n if (!hrefOptions) {\n return href;\n }\n\n const compiler = compile(href, {\n encode: encodeURIComponent,\n validate: false\n });\n\n return compiler(hrefOptions);\n};\n\nexport default compileHref;\n"],"names":["compileHref","href","hrefOptions","compile","encode","encodeURIComponent","validate"],"mappings":";AAcMA,MAAAA,IAAcA,CAClBC,GACAC,MAEKA,IAIYC,EAAQF,GAAM;AAAA,EAC7BG,QAAQC;AAAAA,EACRC,UAAU;AAAA,CACX,EAEeJ,CAAW,IARlBD;"}