@hitachivantara/app-shell-navigation 2.1.12 → 2.1.13
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/hooks/useCurrentNavigationPath.js +19 -24
- package/dist/hooks/useLocation.js +45 -48
- package/dist/hooks/useNavigation.js +105 -121
- package/dist/index.js +2 -6
- package/dist/utils/navigationUtil.js +18 -9
- package/package.json +3 -3
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { useHvMenuItems } from "@hitachivantara/app-shell-shared";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
return paths;
|
|
23
|
-
}, [items, selectedMenuItemId]);
|
|
24
|
-
};
|
|
25
|
-
export {
|
|
26
|
-
useHvCurrentNavigationPath
|
|
3
|
+
//#region src/hooks/useCurrentNavigationPath.ts
|
|
4
|
+
var useHvCurrentNavigationPath = () => {
|
|
5
|
+
const { items, selectedMenuItemId } = useHvMenuItems();
|
|
6
|
+
return useMemo(() => {
|
|
7
|
+
let currentItems = items;
|
|
8
|
+
if (!selectedMenuItemId) return [];
|
|
9
|
+
const paths = [];
|
|
10
|
+
selectedMenuItemId.split("-").forEach((item) => {
|
|
11
|
+
const currentItem = currentItems[Number(item)];
|
|
12
|
+
paths.push({
|
|
13
|
+
label: currentItem.label,
|
|
14
|
+
path: currentItem.data ? void 0 : currentItem.href
|
|
15
|
+
});
|
|
16
|
+
if (currentItem.data) currentItems = currentItem.data;
|
|
17
|
+
});
|
|
18
|
+
return paths;
|
|
19
|
+
}, [items, selectedMenuItemId]);
|
|
27
20
|
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { useHvCurrentNavigationPath };
|
|
@@ -1,54 +1,51 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
|
-
import { useLocation, matchRoutes } from "react-router-dom";
|
|
3
2
|
import { useHvAppShellModel } from "@hitachivantara/app-shell-shared";
|
|
3
|
+
import { matchRoutes, useLocation } from "react-router-dom";
|
|
4
|
+
//#region src/hooks/useLocation.ts
|
|
4
5
|
function indexViews(views) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
children: view.views ? indexViews(view.views) : void 0
|
|
18
|
-
};
|
|
19
|
-
});
|
|
6
|
+
return views.map((view) => {
|
|
7
|
+
const path = view.route.slice(1);
|
|
8
|
+
if (path === "" && (view.views == null || view.views.length === 0)) return {
|
|
9
|
+
path,
|
|
10
|
+
view
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
path,
|
|
14
|
+
view,
|
|
15
|
+
children: view.views ? indexViews(view.views) : void 0
|
|
16
|
+
};
|
|
17
|
+
});
|
|
20
18
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
const useHvLocation = () => {
|
|
46
|
-
const location = useLocation();
|
|
47
|
-
const { mainPanel } = useHvAppShellModel();
|
|
48
|
-
return useMemo(() => {
|
|
49
|
-
return new LocationWithViews(location, mainPanel?.views);
|
|
50
|
-
}, [location, mainPanel?.views]);
|
|
19
|
+
var LocationWithViews = class {
|
|
20
|
+
state;
|
|
21
|
+
key;
|
|
22
|
+
pathname;
|
|
23
|
+
search;
|
|
24
|
+
hash;
|
|
25
|
+
#configViews;
|
|
26
|
+
matches = null;
|
|
27
|
+
constructor(location, views) {
|
|
28
|
+
this.state = location.state;
|
|
29
|
+
this.key = location.key;
|
|
30
|
+
this.pathname = location.pathname;
|
|
31
|
+
this.search = location.search;
|
|
32
|
+
this.hash = location.hash;
|
|
33
|
+
this.#configViews = views ?? [];
|
|
34
|
+
}
|
|
35
|
+
get views() {
|
|
36
|
+
if (this.matches == null) {
|
|
37
|
+
const indexedViews = indexViews(this.#configViews);
|
|
38
|
+
this.matches = matchRoutes(indexedViews, this)?.map((match) => match.route.view) ?? [];
|
|
39
|
+
}
|
|
40
|
+
return this.matches;
|
|
41
|
+
}
|
|
51
42
|
};
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
var useHvLocation = () => {
|
|
44
|
+
const location = useLocation();
|
|
45
|
+
const { mainPanel } = useHvAppShellModel();
|
|
46
|
+
return useMemo(() => {
|
|
47
|
+
return new LocationWithViews(location, mainPanel?.views);
|
|
48
|
+
}, [location, mainPanel?.views]);
|
|
54
49
|
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { useHvLocation };
|
|
@@ -1,130 +1,114 @@
|
|
|
1
|
-
import { useMemo, useContext, useRef, useCallback } from "react";
|
|
2
|
-
import { useNavigate } from "react-router-dom";
|
|
3
|
-
import { useHvAppShellModel, HvAppShellViewContext } from "@hitachivantara/app-shell-shared";
|
|
4
1
|
import compileHref from "../utils/navigationUtil.js";
|
|
5
2
|
import { useHvLocation } from "./useLocation.js";
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { useCallback, useContext, useMemo, useRef } from "react";
|
|
4
|
+
import { HvAppShellViewContext, useHvAppShellModel } from "@hitachivantara/app-shell-shared";
|
|
5
|
+
import { useNavigate } from "react-router-dom";
|
|
6
|
+
//#region src/hooks/useNavigation.ts
|
|
7
|
+
var isViewDestination = (to) => {
|
|
8
|
+
return to.viewBundle !== void 0;
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
var isPathDestination = (to) => {
|
|
11
|
+
return typeof to !== "string" && !isViewDestination(to);
|
|
11
12
|
};
|
|
12
13
|
function getActiveViewRoute(activeViews, depth) {
|
|
13
|
-
|
|
14
|
+
return `/${activeViews.map((view) => view.route.slice(1)).slice(0, depth ?? activeViews.length).filter((route) => route !== "").join("/")}`;
|
|
14
15
|
}
|
|
15
16
|
function isSameBundle(v, bundle, appId) {
|
|
16
|
-
|
|
17
|
+
return v.bundle === `${bundle}` || v.bundle === `${bundle}.js` || v.bundle === `${appId}/${bundle}.js` || v.bundle === `${appId}/${bundle}`;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (options != null) {
|
|
112
|
-
if (options.mode == null) {
|
|
113
|
-
navigateOptions = options;
|
|
114
|
-
} else {
|
|
115
|
-
navigateOptions = { ...options };
|
|
116
|
-
delete navigateOptions.mode;
|
|
117
|
-
if (Object.keys(navigateOptions).length === 0) {
|
|
118
|
-
navigateOptions = void 0;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
navigateReactRouter(path, navigateOptions);
|
|
123
|
-
},
|
|
124
|
-
[getViewRoute, navigateReactRouter]
|
|
125
|
-
);
|
|
126
|
-
return { getViewRoute, navigate };
|
|
127
|
-
};
|
|
128
|
-
export {
|
|
129
|
-
useHvNavigation
|
|
19
|
+
var useHvNavigation = () => {
|
|
20
|
+
const { mainPanel } = useHvAppShellModel();
|
|
21
|
+
const flattenViews = useMemo(() => {
|
|
22
|
+
const flatten = (views, base = "") => {
|
|
23
|
+
return views.reduce((acc, view) => {
|
|
24
|
+
const route = `${base}${view.route}`;
|
|
25
|
+
acc.push({
|
|
26
|
+
...view,
|
|
27
|
+
route
|
|
28
|
+
});
|
|
29
|
+
if (view.views != null) acc.push(...flatten(view.views, route));
|
|
30
|
+
return acc;
|
|
31
|
+
}, []);
|
|
32
|
+
};
|
|
33
|
+
return flatten(mainPanel?.views ?? []);
|
|
34
|
+
}, [mainPanel?.views]);
|
|
35
|
+
const viewContext = useContext(HvAppShellViewContext);
|
|
36
|
+
const navigateReactRouter = useNavigate();
|
|
37
|
+
const location = useHvLocation();
|
|
38
|
+
const locationRef = useRef(location);
|
|
39
|
+
locationRef.current = location;
|
|
40
|
+
/**
|
|
41
|
+
* Utility to search for the route of a View on the App Shell configuration.
|
|
42
|
+
*
|
|
43
|
+
* The search can be performed in different modes:
|
|
44
|
+
* - "auto": Searches within views whose route is a subpath of the current active view, progressively going up path segments until a match is found.
|
|
45
|
+
* - "top": Finds the view closest to the root, i.e. with the least number of path segments.
|
|
46
|
+
*
|
|
47
|
+
* If multiple views match the search criteria, the function returns the one that appears first in the App Shell configuration.
|
|
48
|
+
*
|
|
49
|
+
* @param viewBundleDir The application view bundle directory name and optional route parameters.
|
|
50
|
+
* @param mode The search mode to use. Defaults to "auto".
|
|
51
|
+
*
|
|
52
|
+
* @returns The compiled route or undefined if none was found.
|
|
53
|
+
*/
|
|
54
|
+
const getViewRoute = useCallback((viewBundleDir, { mode = "auto" } = {}) => {
|
|
55
|
+
let viewBundle;
|
|
56
|
+
let pathParams;
|
|
57
|
+
let search;
|
|
58
|
+
let hash;
|
|
59
|
+
if (isViewDestination(viewBundleDir)) ({viewBundle, pathParams, search, hash} = viewBundleDir);
|
|
60
|
+
else viewBundle = viewBundleDir;
|
|
61
|
+
const bundleWithReplacedPlaceholders = viewBundle.replace(/\$/, "_");
|
|
62
|
+
let appId;
|
|
63
|
+
let bundle;
|
|
64
|
+
if (bundleWithReplacedPlaceholders.startsWith("/")) {
|
|
65
|
+
appId = viewContext?.id;
|
|
66
|
+
bundle = bundleWithReplacedPlaceholders.slice(1);
|
|
67
|
+
} else bundle = bundleWithReplacedPlaceholders;
|
|
68
|
+
let activeViews = [];
|
|
69
|
+
if (mode !== "top") activeViews = locationRef.current.views;
|
|
70
|
+
let route;
|
|
71
|
+
const matchingViews = flattenViews.filter((v) => isSameBundle(v, bundle, appId)).toSorted((a, b) => {
|
|
72
|
+
return (a.route.match(/\//g) ?? []).length - (b.route.match(/\//g) ?? []).length;
|
|
73
|
+
});
|
|
74
|
+
if (matchingViews.length > 0) {
|
|
75
|
+
if (mode === "top" || matchingViews.length === 1) route = matchingViews[0].route;
|
|
76
|
+
else if (mode === "auto") {
|
|
77
|
+
let path = `${getActiveViewRoute(activeViews)}/`;
|
|
78
|
+
while (route == null) {
|
|
79
|
+
const innerPath = path;
|
|
80
|
+
route = matchingViews.find((v) => v.route.startsWith(innerPath))?.route;
|
|
81
|
+
path = path.replace(/\/[^/]*\/?$/, "/");
|
|
82
|
+
if (path === "") break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return route ? `${compileHref(route, pathParams)}${search ?? ""}${hash ?? ""}` : void 0;
|
|
87
|
+
}, [flattenViews, viewContext?.id]);
|
|
88
|
+
return {
|
|
89
|
+
getViewRoute,
|
|
90
|
+
navigate: useCallback((to, options) => {
|
|
91
|
+
let path;
|
|
92
|
+
if (isPathDestination(to)) path = to;
|
|
93
|
+
else {
|
|
94
|
+
const route = getViewRoute(to, { mode: options?.mode });
|
|
95
|
+
if (route == null) if (typeof to === "string") path = to;
|
|
96
|
+
else {
|
|
97
|
+
console.warn(`Navigate request to a non existing path [${to.viewBundle}]. Skipping`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
else path = route;
|
|
101
|
+
}
|
|
102
|
+
let navigateOptions;
|
|
103
|
+
if (options != null) if (options.mode == null) navigateOptions = options;
|
|
104
|
+
else {
|
|
105
|
+
navigateOptions = { ...options };
|
|
106
|
+
delete navigateOptions.mode;
|
|
107
|
+
if (Object.keys(navigateOptions).length === 0) navigateOptions = void 0;
|
|
108
|
+
}
|
|
109
|
+
navigateReactRouter(path, navigateOptions);
|
|
110
|
+
}, [getViewRoute, navigateReactRouter])
|
|
111
|
+
};
|
|
130
112
|
};
|
|
113
|
+
//#endregion
|
|
114
|
+
export { useHvNavigation };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { useHvCurrentNavigationPath } from "./hooks/useCurrentNavigationPath.js";
|
|
2
|
-
import { useHvNavigation } from "./hooks/useNavigation.js";
|
|
3
2
|
import { useHvLocation } from "./hooks/useLocation.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
useHvLocation,
|
|
7
|
-
useHvNavigation
|
|
8
|
-
};
|
|
3
|
+
import { useHvNavigation } from "./hooks/useNavigation.js";
|
|
4
|
+
export { useHvCurrentNavigationPath, useHvLocation, useHvNavigation };
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { compile } from "path-to-regexp";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
//#region src/utils/navigationUtil.ts
|
|
3
|
+
/**
|
|
4
|
+
* Utility that replaces the href placeholders with the href options provided.
|
|
5
|
+
* The href parameter must not contain 'search' nor 'hash' parts.
|
|
6
|
+
* @example
|
|
7
|
+
* // returns '/home/2'
|
|
8
|
+
* // href: '/home/:id', hrefOptions: '{id: 2}'
|
|
9
|
+
*
|
|
10
|
+
* @param href The string to be compiled.
|
|
11
|
+
* @param hrefOptions The options to replace the placeholders on the href.
|
|
12
|
+
*
|
|
13
|
+
* @returns The compiled href
|
|
14
|
+
*/
|
|
15
|
+
var compileHref = (href, hrefOptions) => {
|
|
16
|
+
if (!hrefOptions) return href;
|
|
17
|
+
return compile(href)(hrefOptions);
|
|
11
18
|
};
|
|
19
|
+
//#endregion
|
|
20
|
+
export { compileHref as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hitachivantara/app-shell-navigation",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Hitachi Vantara UI Kit Team",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"bugs": "https://github.com/pentaho/hv-uikit-react/issues",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@hitachivantara/app-shell-shared": "^2.3.
|
|
18
|
+
"@hitachivantara/app-shell-shared": "^2.3.2",
|
|
19
19
|
"path-to-regexp": "^8.1.0"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public",
|
|
30
30
|
"directory": "package"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "65c4f4394e8f8c7cccb58203e1c08c6832434638",
|
|
33
33
|
"exports": {
|
|
34
34
|
".": {
|
|
35
35
|
"types": "./dist/index.d.ts",
|