@wallarm-org/design-system 0.50.1 → 0.50.2-rc-feature-shell.1
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/components/AppShell/story-content/_storyConfigRenderer.d.ts +1 -1
- package/dist/components/AppShell/story-content/_storyConfigRenderer.js +15 -29
- package/dist/components/AppShell/story-content/_storyLib.js +1 -1
- package/dist/components/AppShell/story-content/_storyNavConfigs.d.ts +1 -1
- package/dist/components/NavPanel/NavPanelHeader.js +1 -1
- package/dist/components/Page/PageContent.js +1 -1
- package/dist/components/Page/PageHeader.js +1 -1
- package/dist/components/{ProductNav → RemoteShell}/HeaderActions.d.ts +1 -1
- package/dist/components/{ProductNav → RemoteShell}/NavItemsList.d.ts +1 -1
- package/dist/components/RemoteShell/NavPanelContent.d.ts +6 -0
- package/dist/components/RemoteShell/NavPanelContent.js +64 -0
- package/dist/components/RemoteShell/RemoteShell.d.ts +7 -0
- package/dist/components/RemoteShell/RemoteShell.js +112 -9
- package/dist/components/RemoteShell/RemoteShellBreadcrumb.js +39 -4
- package/dist/components/RemoteShell/RemoteShellContent.d.ts +1 -0
- package/dist/components/RemoteShell/RemoteShellContent.js +7 -3
- package/dist/components/RemoteShell/RemoteShellPanel.d.ts +4 -2
- package/dist/components/RemoteShell/RemoteShellPanel.js +76 -3
- package/dist/components/RemoteShell/index.d.ts +2 -0
- package/dist/components/RemoteShell/index.js +2 -1
- package/dist/components/{ProductNav/ProductNavContext.d.ts → RemoteShell/model/RemoteShellContext.d.ts} +3 -3
- package/dist/components/RemoteShell/model/RemoteShellContext.js +9 -0
- package/dist/components/RemoteShell/model/index.d.ts +5 -0
- package/dist/components/RemoteShell/model/index.js +5 -0
- package/dist/components/{ProductNav → RemoteShell/model}/types.d.ts +1 -3
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2 -3
- package/dist/metadata/components.json +35 -303
- package/package.json +1 -1
- package/dist/components/ProductNav/ProductNav.d.ts +0 -13
- package/dist/components/ProductNav/ProductNav.js +0 -109
- package/dist/components/ProductNav/ProductNavBreadcrumbs.d.ts +0 -2
- package/dist/components/ProductNav/ProductNavBreadcrumbs.js +0 -38
- package/dist/components/ProductNav/ProductNavContext.js +0 -9
- package/dist/components/ProductNav/ProductNavPanel.d.ts +0 -6
- package/dist/components/ProductNav/ProductNavPanel.js +0 -107
- package/dist/components/ProductNav/index.d.ts +0 -11
- package/dist/components/ProductNav/index.js +0 -10
- package/dist/components/ProductNav/useProductNav.d.ts +0 -16
- package/dist/components/ProductNav/useProductNav.js +0 -19
- /package/dist/components/{ProductNav → RemoteShell}/HeaderActions.js +0 -0
- /package/dist/components/{ProductNav → RemoteShell}/NavItemsList.js +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/matchNav.d.ts +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/matchNav.js +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/navUtils.d.ts +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/navUtils.js +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/types.js +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/useDrillTransition.d.ts +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/useDrillTransition.js +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/useLocationPathname.d.ts +0 -0
- /package/dist/components/{ProductNav → RemoteShell/model}/useLocationPathname.js +0 -0
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
-
import { NavPanel, NavPanelHeader } from "../../NavPanel/index.js";
|
|
4
3
|
import { Page, PageContent, PageHeader, PageTitle } from "../../Page/index.js";
|
|
5
|
-
import {
|
|
6
|
-
import { RemoteShell, RemoteShellBreadcrumb, RemoteShellContent, RemoteShellPanel } from "../../RemoteShell/index.js";
|
|
4
|
+
import { RemoteShell, RemoteShellBreadcrumb, RemoteShellContent, RemoteShellPanel, useRemoteShellContext } from "../../RemoteShell/index.js";
|
|
7
5
|
import { HomeContent } from "./_storyHomeContent.js";
|
|
8
6
|
import { PRODUCT_CONFIGS } from "./_storyLib.js";
|
|
9
7
|
const RemotePageContent = ()=>{
|
|
10
|
-
const { breadcrumbSegments } =
|
|
8
|
+
const { breadcrumbSegments } = useRemoteShellContext();
|
|
11
9
|
const lastSegment = breadcrumbSegments[breadcrumbSegments.length - 1];
|
|
12
10
|
const pageTitle = lastSegment?.label ?? '';
|
|
13
11
|
const fullPath = breadcrumbSegments.map((s)=>s.label).join(' / ');
|
|
@@ -44,36 +42,24 @@ const ConfigRemote = ({ config, basePath })=>{
|
|
|
44
42
|
}, [
|
|
45
43
|
config.productLabel
|
|
46
44
|
]);
|
|
47
|
-
|
|
48
|
-
children: [
|
|
49
|
-
/*#__PURE__*/ jsx(RemoteShellPanel, {
|
|
50
|
-
children: /*#__PURE__*/ jsxs(NavPanel, {
|
|
51
|
-
children: [
|
|
52
|
-
/*#__PURE__*/ jsx(NavPanelHeader, {
|
|
53
|
-
children: config.productLabel
|
|
54
|
-
}),
|
|
55
|
-
/*#__PURE__*/ jsx(NavPanelSkeleton, {
|
|
56
|
-
count: 6
|
|
57
|
-
})
|
|
58
|
-
]
|
|
59
|
-
})
|
|
60
|
-
}),
|
|
61
|
-
/*#__PURE__*/ jsx(RemoteShellContent, {})
|
|
62
|
-
]
|
|
63
|
-
});
|
|
64
|
-
return /*#__PURE__*/ jsx(ProductNav, {
|
|
45
|
+
return /*#__PURE__*/ jsx(RemoteShell, {
|
|
65
46
|
config: config,
|
|
66
47
|
basePath: basePath,
|
|
67
|
-
children: /*#__PURE__*/ jsxs(
|
|
48
|
+
children: loading ? /*#__PURE__*/ jsxs(Fragment, {
|
|
68
49
|
children: [
|
|
69
50
|
/*#__PURE__*/ jsx(RemoteShellPanel, {
|
|
70
|
-
|
|
71
|
-
resizable: true
|
|
72
|
-
})
|
|
51
|
+
isLoading: true
|
|
73
52
|
}),
|
|
74
|
-
/*#__PURE__*/ jsx(
|
|
75
|
-
|
|
53
|
+
/*#__PURE__*/ jsx(RemoteShellContent, {
|
|
54
|
+
isLoading: true
|
|
55
|
+
})
|
|
56
|
+
]
|
|
57
|
+
}) : /*#__PURE__*/ jsxs(Fragment, {
|
|
58
|
+
children: [
|
|
59
|
+
/*#__PURE__*/ jsx(RemoteShellPanel, {
|
|
60
|
+
resizable: true
|
|
76
61
|
}),
|
|
62
|
+
/*#__PURE__*/ jsx(RemoteShellBreadcrumb, {}),
|
|
77
63
|
/*#__PURE__*/ jsx(RemoteShellContent, {
|
|
78
64
|
children: /*#__PURE__*/ jsx(RemotePageContent, {})
|
|
79
65
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findFirstLinkPath, pushPathname } from "../../
|
|
1
|
+
import { findFirstLinkPath, pushPathname } from "../../RemoteShell/index.js";
|
|
2
2
|
import { aiHypervisorNavConfig, edgeNavConfig, infraDiscoveryNavConfig, securityTestingNavConfig, settingsNavConfig } from "./_storyNavConfigs.js";
|
|
3
3
|
const KNOWN_PRODUCTS = [
|
|
4
4
|
'home',
|
|
@@ -9,7 +9,7 @@ const NavPanelHeader = ({ ref, className, children, ...props })=>{
|
|
|
9
9
|
ref: ref,
|
|
10
10
|
"data-slot": "nav-panel-header",
|
|
11
11
|
"data-testid": testId,
|
|
12
|
-
className: cn('sticky top-0 z-10 flex shrink-0 items-center p-4', className),
|
|
12
|
+
className: cn('sticky top-0 z-10 flex shrink-0 items-center p-4 bg-bg-surface-2', className),
|
|
13
13
|
children: /*#__PURE__*/ jsx(Text, {
|
|
14
14
|
size: "sm",
|
|
15
15
|
weight: "medium",
|
|
@@ -8,7 +8,7 @@ const PageContent = ({ ref, children, className, ...props })=>{
|
|
|
8
8
|
ref: ref,
|
|
9
9
|
"data-testid": testId,
|
|
10
10
|
"data-slot": "page-content",
|
|
11
|
-
className: cn('flex-1 min-h-0 overflow-auto px-
|
|
11
|
+
className: cn('flex-1 min-h-0 overflow-auto px-16', className),
|
|
12
12
|
children: children
|
|
13
13
|
});
|
|
14
14
|
};
|
|
@@ -8,7 +8,7 @@ const PageHeader = ({ ref, sticky, children, className, ...props })=>{
|
|
|
8
8
|
ref: ref,
|
|
9
9
|
"data-testid": testId,
|
|
10
10
|
"data-slot": "page-header",
|
|
11
|
-
className: cn('flex items-center px-
|
|
11
|
+
className: cn('flex items-center px-16 pb-16 gap-12', sticky && 'sticky top-0 z-10 bg-bg-surface-2', className),
|
|
12
12
|
children: children
|
|
13
13
|
});
|
|
14
14
|
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { NavPanelBack, NavPanelDivider, NavPanelHeader } from "../NavPanel/index.js";
|
|
3
|
+
import { Text } from "../Text/index.js";
|
|
4
|
+
import { HeaderActions } from "./HeaderActions.js";
|
|
5
|
+
import { findDrillNode, useRemoteShellContext } from "./model/index.js";
|
|
6
|
+
import { NavItemsList } from "./NavItemsList.js";
|
|
7
|
+
const NavPanelContent = ({ level })=>{
|
|
8
|
+
const { config, navStack, effectiveActiveItemId, navigate, drillInto, goBack } = useRemoteShellContext();
|
|
9
|
+
const entry = navStack[Math.min(level, navStack.length - 1)];
|
|
10
|
+
const hasHeaderActions = !!config.headerActions?.length;
|
|
11
|
+
if (0 === level) return /*#__PURE__*/ jsxs(Fragment, {
|
|
12
|
+
children: [
|
|
13
|
+
hasHeaderActions ? /*#__PURE__*/ jsxs("div", {
|
|
14
|
+
className: "sticky top-0 z-10 flex shrink-0 items-center justify-between p-4 bg-bg-surface-2",
|
|
15
|
+
children: [
|
|
16
|
+
/*#__PURE__*/ jsx(Text, {
|
|
17
|
+
size: "sm",
|
|
18
|
+
weight: "medium",
|
|
19
|
+
children: config.productLabel
|
|
20
|
+
}),
|
|
21
|
+
/*#__PURE__*/ jsx(HeaderActions, {
|
|
22
|
+
actions: config.headerActions
|
|
23
|
+
})
|
|
24
|
+
]
|
|
25
|
+
}) : /*#__PURE__*/ jsx(NavPanelHeader, {
|
|
26
|
+
children: config.productLabel
|
|
27
|
+
}),
|
|
28
|
+
/*#__PURE__*/ jsx(NavItemsList, {
|
|
29
|
+
items: config.items,
|
|
30
|
+
activeItemId: effectiveActiveItemId,
|
|
31
|
+
onNavigate: navigate,
|
|
32
|
+
onDrillClick: drillInto
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
const parentEntry = navStack[level - 1];
|
|
37
|
+
const drillNode = findDrillNode(parentEntry.items, parentEntry.activeItemId);
|
|
38
|
+
const backLabel = drillNode?.label ?? 'Back';
|
|
39
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
40
|
+
children: [
|
|
41
|
+
/*#__PURE__*/ jsxs("div", {
|
|
42
|
+
className: "sticky top-0 z-10 flex flex-col gap-2 bg-bg-surface-1",
|
|
43
|
+
children: [
|
|
44
|
+
/*#__PURE__*/ jsx(NavPanelHeader, {
|
|
45
|
+
children: entry.title
|
|
46
|
+
}),
|
|
47
|
+
/*#__PURE__*/ jsx(NavPanelBack, {
|
|
48
|
+
onClick: goBack,
|
|
49
|
+
children: backLabel
|
|
50
|
+
}),
|
|
51
|
+
/*#__PURE__*/ jsx(NavPanelDivider, {})
|
|
52
|
+
]
|
|
53
|
+
}),
|
|
54
|
+
/*#__PURE__*/ jsx(NavItemsList, {
|
|
55
|
+
items: entry.items,
|
|
56
|
+
activeItemId: effectiveActiveItemId,
|
|
57
|
+
onNavigate: navigate,
|
|
58
|
+
onDrillClick: drillInto
|
|
59
|
+
})
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
NavPanelContent.displayName = 'NavPanelContent';
|
|
64
|
+
export { NavPanelContent };
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
2
|
import { type TestableProps } from '../../utils/testId';
|
|
3
|
+
import type { NavConfig } from './model';
|
|
3
4
|
export interface RemoteShellProps extends HTMLAttributes<HTMLDivElement>, TestableProps {
|
|
4
5
|
ref?: Ref<HTMLDivElement>;
|
|
5
6
|
children?: ReactNode;
|
|
7
|
+
/** Navigation config used to build nav state for sub-components. */
|
|
8
|
+
config: NavConfig;
|
|
9
|
+
/** URL prefix stripped before matching and prepended when navigating (e.g. `"/edge"`). */
|
|
10
|
+
basePath?: string;
|
|
11
|
+
/** Custom navigation handler for router integration (React Router, Next.js, etc.). */
|
|
12
|
+
onNavigate?: (pathname: string) => void;
|
|
6
13
|
}
|
|
7
14
|
export declare const RemoteShell: FC<RemoteShellProps>;
|
|
@@ -1,16 +1,119 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
3
|
import { cn } from "../../utils/cn.js";
|
|
3
4
|
import { TestIdProvider } from "../../utils/testId.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
import { RemoteShellContextProvider, findFirstLinkPath, matchNav, pushPathname, useLocationPathname } from "./model/index.js";
|
|
6
|
+
const RemoteShell = ({ ref, className, children, config, basePath, onNavigate, 'data-testid': testId, ...props })=>{
|
|
7
|
+
const fullPathname = useLocationPathname();
|
|
8
|
+
const pathname = basePath && fullPathname.startsWith(basePath) ? fullPathname.slice(basePath.length) || '/' : fullPathname;
|
|
9
|
+
const setPathname = useCallback((next)=>{
|
|
10
|
+
const fullPath = basePath ? `${basePath}${next}` : next;
|
|
11
|
+
if (onNavigate) onNavigate(fullPath);
|
|
12
|
+
else pushPathname(fullPath);
|
|
13
|
+
}, [
|
|
14
|
+
basePath,
|
|
15
|
+
onNavigate
|
|
16
|
+
]);
|
|
17
|
+
const { navStack, breadcrumbSegments, activeItemId } = useMemo(()=>matchNav(pathname, config), [
|
|
18
|
+
pathname,
|
|
19
|
+
config
|
|
20
|
+
]);
|
|
21
|
+
const urlDrillLevel = navStack.length - 1;
|
|
22
|
+
const [visualDrillLevel, setVisualDrillLevel] = useState(null);
|
|
23
|
+
useEffect(()=>{
|
|
24
|
+
setVisualDrillLevel(null);
|
|
25
|
+
}, [
|
|
26
|
+
pathname
|
|
27
|
+
]);
|
|
28
|
+
const effectiveDrillLevel = visualDrillLevel ?? urlDrillLevel;
|
|
29
|
+
const effectiveActiveItemId = effectiveDrillLevel < urlDrillLevel ? navStack[effectiveDrillLevel]?.activeItemId ?? activeItemId : activeItemId;
|
|
30
|
+
const navigate = useCallback((path)=>{
|
|
31
|
+
setVisualDrillLevel(null);
|
|
32
|
+
const segments = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
|
|
33
|
+
const prefixSegments = segments.slice(0, 2 * effectiveDrillLevel);
|
|
34
|
+
setPathname(`/${[
|
|
35
|
+
...prefixSegments,
|
|
36
|
+
path
|
|
37
|
+
].join('/')}`);
|
|
38
|
+
}, [
|
|
39
|
+
effectiveDrillLevel,
|
|
40
|
+
pathname,
|
|
41
|
+
setPathname
|
|
42
|
+
]);
|
|
43
|
+
const drillInto = useCallback((drill)=>{
|
|
44
|
+
setVisualDrillLevel(null);
|
|
45
|
+
const segments = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
|
|
46
|
+
const prefixSegments = segments.slice(0, 2 * effectiveDrillLevel);
|
|
47
|
+
const defaultEntity = drill.entities?.[0]?.id ?? 'default';
|
|
48
|
+
const firstChildPath = findFirstLinkPath(drill.children) ?? '';
|
|
49
|
+
setPathname(`/${[
|
|
50
|
+
...prefixSegments,
|
|
51
|
+
drill.path,
|
|
52
|
+
defaultEntity,
|
|
53
|
+
firstChildPath
|
|
54
|
+
].join('/')}`);
|
|
55
|
+
}, [
|
|
56
|
+
effectiveDrillLevel,
|
|
57
|
+
pathname,
|
|
58
|
+
setPathname
|
|
59
|
+
]);
|
|
60
|
+
const goBack = useCallback(()=>{
|
|
61
|
+
setVisualDrillLevel((prev)=>{
|
|
62
|
+
const current = prev ?? urlDrillLevel;
|
|
63
|
+
return Math.max(current - 1, 0);
|
|
64
|
+
});
|
|
65
|
+
}, [
|
|
66
|
+
urlDrillLevel
|
|
67
|
+
]);
|
|
68
|
+
const navigateTo = useCallback((href)=>{
|
|
69
|
+
setVisualDrillLevel(null);
|
|
70
|
+
if ('/' === href) {
|
|
71
|
+
const firstPath = findFirstLinkPath(config.items) ?? '';
|
|
72
|
+
setPathname(`/${firstPath}`);
|
|
73
|
+
} else setPathname(href);
|
|
74
|
+
}, [
|
|
75
|
+
config.items,
|
|
76
|
+
setPathname
|
|
77
|
+
]);
|
|
78
|
+
const navCtxValue = useMemo(()=>({
|
|
79
|
+
config,
|
|
80
|
+
pathname,
|
|
81
|
+
navStack,
|
|
82
|
+
breadcrumbSegments,
|
|
83
|
+
activeItemId,
|
|
84
|
+
drillLevel: effectiveDrillLevel,
|
|
85
|
+
effectiveActiveItemId,
|
|
86
|
+
navigate,
|
|
87
|
+
drillInto,
|
|
88
|
+
goBack,
|
|
89
|
+
navigateTo
|
|
90
|
+
}), [
|
|
91
|
+
config,
|
|
92
|
+
pathname,
|
|
93
|
+
navStack,
|
|
94
|
+
breadcrumbSegments,
|
|
95
|
+
activeItemId,
|
|
96
|
+
effectiveDrillLevel,
|
|
97
|
+
effectiveActiveItemId,
|
|
98
|
+
navigate,
|
|
99
|
+
drillInto,
|
|
100
|
+
goBack,
|
|
101
|
+
navigateTo
|
|
102
|
+
]);
|
|
103
|
+
return /*#__PURE__*/ jsx(RemoteShellContextProvider, {
|
|
104
|
+
value: navCtxValue,
|
|
105
|
+
children: /*#__PURE__*/ jsx(TestIdProvider, {
|
|
106
|
+
value: testId,
|
|
107
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
108
|
+
...props,
|
|
109
|
+
ref: ref,
|
|
110
|
+
"data-slot": "remote-shell",
|
|
111
|
+
"data-testid": testId,
|
|
112
|
+
className: cn('grid h-full overflow-hidden overscroll-none [grid-template-areas:"panel_breadcrumb""panel_content"] [grid-template-columns:auto_1fr] [grid-template-rows:auto_1fr]', className),
|
|
113
|
+
children: children
|
|
114
|
+
})
|
|
13
115
|
})
|
|
14
116
|
});
|
|
117
|
+
};
|
|
15
118
|
RemoteShell.displayName = 'RemoteShell';
|
|
16
119
|
export { RemoteShell };
|
|
@@ -1,15 +1,50 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
|
+
import { Breadcrumbs, BreadcrumbsItem, BreadcrumbsScopeSwitcher } from "../Breadcrumbs/index.js";
|
|
5
|
+
import { useRemoteShellContext } from "./model/index.js";
|
|
4
6
|
const RemoteShellBreadcrumb = ({ ref, className, children, ...props })=>{
|
|
5
7
|
const testId = useTestId('breadcrumb');
|
|
6
|
-
|
|
8
|
+
const { breadcrumbSegments, navigateTo } = useRemoteShellContext();
|
|
9
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
7
10
|
...props,
|
|
8
11
|
ref: ref,
|
|
9
12
|
"data-slot": "remote-shell-breadcrumb",
|
|
10
13
|
"data-testid": testId,
|
|
11
|
-
className: cn('[grid-area:breadcrumb] flex items-center px-
|
|
12
|
-
children:
|
|
14
|
+
className: cn('[grid-area:breadcrumb] flex items-center gap-8 px-16 py-8', className),
|
|
15
|
+
children: [
|
|
16
|
+
/*#__PURE__*/ jsx(Breadcrumbs, {
|
|
17
|
+
"data-slot": "nav-breadcrumbs",
|
|
18
|
+
children: breadcrumbSegments.map((segment, i)=>{
|
|
19
|
+
const isLast = i === breadcrumbSegments.length - 1;
|
|
20
|
+
if ('scope-switcher' === segment.type) {
|
|
21
|
+
if (segment.scopeItems?.length && segment.paramValue) return /*#__PURE__*/ jsx(BreadcrumbsScopeSwitcher, {
|
|
22
|
+
value: segment.paramValue,
|
|
23
|
+
items: segment.scopeItems,
|
|
24
|
+
onSelect: (item)=>navigateTo?.(item.href),
|
|
25
|
+
children: segment.label
|
|
26
|
+
}, i);
|
|
27
|
+
return /*#__PURE__*/ jsx(BreadcrumbsItem, {
|
|
28
|
+
children: segment.label
|
|
29
|
+
}, i);
|
|
30
|
+
}
|
|
31
|
+
if ('link' === segment.type && !isLast) return /*#__PURE__*/ jsx(BreadcrumbsItem, {
|
|
32
|
+
href: segment.href,
|
|
33
|
+
onClick: (e)=>{
|
|
34
|
+
if (navigateTo && segment.href) {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
navigateTo(segment.href);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
children: segment.label
|
|
40
|
+
}, i);
|
|
41
|
+
return /*#__PURE__*/ jsx(BreadcrumbsItem, {
|
|
42
|
+
children: segment.label
|
|
43
|
+
}, i);
|
|
44
|
+
})
|
|
45
|
+
}),
|
|
46
|
+
children
|
|
47
|
+
]
|
|
13
48
|
});
|
|
14
49
|
};
|
|
15
50
|
RemoteShellBreadcrumb.displayName = 'RemoteShellBreadcrumb';
|
|
@@ -2,5 +2,6 @@ import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
|
|
|
2
2
|
export interface RemoteShellContentProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
3
|
ref?: Ref<HTMLDivElement>;
|
|
4
4
|
children?: ReactNode;
|
|
5
|
+
isLoading?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export declare const RemoteShellContent: FC<RemoteShellContentProps>;
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
|
-
|
|
4
|
+
import { Loader } from "../Loader/index.js";
|
|
5
|
+
const RemoteShellContent = ({ ref, className, children, isLoading, ...props })=>{
|
|
5
6
|
const testId = useTestId('content');
|
|
6
7
|
return /*#__PURE__*/ jsx("div", {
|
|
7
8
|
...props,
|
|
8
9
|
ref: ref,
|
|
9
10
|
"data-slot": "remote-shell-content",
|
|
10
11
|
"data-testid": testId,
|
|
11
|
-
className: cn('[grid-area:content] min-h-0 overflow-auto overscroll-none
|
|
12
|
-
children:
|
|
12
|
+
className: cn('[grid-area:content] min-h-0 overflow-auto overscroll-none [scrollbar-width:thin]', isLoading && 'flex items-center justify-center', className),
|
|
13
|
+
children: isLoading ? /*#__PURE__*/ jsx(Loader, {
|
|
14
|
+
size: "3xl",
|
|
15
|
+
color: "brand"
|
|
16
|
+
}) : children
|
|
13
17
|
});
|
|
14
18
|
};
|
|
15
19
|
RemoteShellContent.displayName = 'RemoteShellContent';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { FC, HTMLAttributes,
|
|
1
|
+
import type { FC, HTMLAttributes, Ref } from 'react';
|
|
2
2
|
export interface RemoteShellPanelProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
3
|
ref?: Ref<HTMLDivElement>;
|
|
4
|
-
|
|
4
|
+
resizable?: boolean;
|
|
5
|
+
isLoading?: boolean;
|
|
6
|
+
loaderCount?: number;
|
|
5
7
|
}
|
|
6
8
|
export declare const RemoteShellPanel: FC<RemoteShellPanelProps>;
|
|
@@ -1,15 +1,88 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
|
-
|
|
4
|
+
import { NavPanel, NavPanelHeader, NavPanelSkeleton } from "../NavPanel/index.js";
|
|
5
|
+
import { useRemoteShellContext } from "./model/index.js";
|
|
6
|
+
import { DRILL_ANIMATION_DURATION, DRILL_ANIMATION_EASING, useDrillTransition } from "./model/useDrillTransition.js";
|
|
7
|
+
import { NavPanelContent } from "./NavPanelContent.js";
|
|
8
|
+
const RemoteShellPanel = ({ ref, className, resizable, isLoading, loaderCount = 6, ...props })=>{
|
|
5
9
|
const testId = useTestId('panel');
|
|
10
|
+
const { config, drillLevel } = useRemoteShellContext();
|
|
11
|
+
const { transition, clearTransition } = useDrillTransition(drillLevel);
|
|
12
|
+
if (isLoading) return /*#__PURE__*/ jsx("div", {
|
|
13
|
+
...props,
|
|
14
|
+
ref: ref,
|
|
15
|
+
"data-slot": "remote-shell-panel",
|
|
16
|
+
"data-testid": testId,
|
|
17
|
+
className: cn('[grid-area:panel] min-h-0', className),
|
|
18
|
+
children: /*#__PURE__*/ jsxs(NavPanel, {
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ jsx(NavPanelHeader, {
|
|
21
|
+
children: config.productLabel
|
|
22
|
+
}),
|
|
23
|
+
/*#__PURE__*/ jsx(NavPanelSkeleton, {
|
|
24
|
+
count: loaderCount
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
if (transition) {
|
|
30
|
+
const isForward = 'forward' === transition.direction;
|
|
31
|
+
const slideAnim = isForward ? 'ds-nav-drill-forward' : 'ds-nav-drill-backward';
|
|
32
|
+
const timing = `${DRILL_ANIMATION_DURATION} ${DRILL_ANIMATION_EASING} both`;
|
|
33
|
+
return /*#__PURE__*/ jsx("div", {
|
|
34
|
+
...props,
|
|
35
|
+
ref: ref,
|
|
36
|
+
"data-slot": "remote-shell-panel",
|
|
37
|
+
"data-testid": testId,
|
|
38
|
+
className: cn('[grid-area:panel] min-h-0', className),
|
|
39
|
+
children: /*#__PURE__*/ jsx(NavPanel, {
|
|
40
|
+
resizable: resizable,
|
|
41
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
42
|
+
className: "min-h-0 flex-1 overflow-hidden",
|
|
43
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
44
|
+
className: "flex motion-reduce:animate-none",
|
|
45
|
+
style: {
|
|
46
|
+
animation: `${slideAnim} ${timing}`
|
|
47
|
+
},
|
|
48
|
+
onAnimationEnd: clearTransition,
|
|
49
|
+
children: [
|
|
50
|
+
/*#__PURE__*/ jsx("div", {
|
|
51
|
+
className: "flex w-full shrink-0 flex-col gap-2 motion-reduce:animate-none",
|
|
52
|
+
style: {
|
|
53
|
+
animation: `${isForward ? 'ds-nav-blur-out' : 'ds-nav-blur-in'} ${timing}`
|
|
54
|
+
},
|
|
55
|
+
children: /*#__PURE__*/ jsx(NavPanelContent, {
|
|
56
|
+
level: isForward ? transition.fromLevel : drillLevel
|
|
57
|
+
})
|
|
58
|
+
}),
|
|
59
|
+
/*#__PURE__*/ jsx("div", {
|
|
60
|
+
className: "flex w-full shrink-0 flex-col gap-2 motion-reduce:animate-none",
|
|
61
|
+
style: {
|
|
62
|
+
animation: `${isForward ? 'ds-nav-blur-in' : 'ds-nav-blur-out'} ${timing}`
|
|
63
|
+
},
|
|
64
|
+
children: /*#__PURE__*/ jsx(NavPanelContent, {
|
|
65
|
+
level: isForward ? drillLevel : transition.fromLevel
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
]
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
}
|
|
6
74
|
return /*#__PURE__*/ jsx("div", {
|
|
7
75
|
...props,
|
|
8
76
|
ref: ref,
|
|
9
77
|
"data-slot": "remote-shell-panel",
|
|
10
78
|
"data-testid": testId,
|
|
11
79
|
className: cn('[grid-area:panel] min-h-0', className),
|
|
12
|
-
children:
|
|
80
|
+
children: /*#__PURE__*/ jsx(NavPanel, {
|
|
81
|
+
resizable: resizable,
|
|
82
|
+
children: /*#__PURE__*/ jsx(NavPanelContent, {
|
|
83
|
+
level: drillLevel
|
|
84
|
+
})
|
|
85
|
+
})
|
|
13
86
|
});
|
|
14
87
|
};
|
|
15
88
|
RemoteShellPanel.displayName = 'RemoteShellPanel';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export type { BreadcrumbSegment, NavConfig, NavConfigDrill, NavConfigGroup, NavConfigHeaderAction, NavConfigLink, NavConfigNode, NavConfigSectionHeader, NavStackEntry, RemoteShellContextValue, } from './model';
|
|
2
|
+
export { findFirstLinkPath, pushPathname, useLocationPathname, useRemoteShellContext, } from './model';
|
|
1
3
|
export { RemoteShell, type RemoteShellProps } from './RemoteShell';
|
|
2
4
|
export { RemoteShellBreadcrumb, type RemoteShellBreadcrumbProps } from './RemoteShellBreadcrumb';
|
|
3
5
|
export { RemoteShellContent, type RemoteShellContentProps } from './RemoteShellContent';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { findFirstLinkPath, pushPathname, useLocationPathname, useRemoteShellContext } from "./model/index.js";
|
|
1
2
|
import { RemoteShell } from "./RemoteShell.js";
|
|
2
3
|
import { RemoteShellBreadcrumb } from "./RemoteShellBreadcrumb.js";
|
|
3
4
|
import { RemoteShellContent } from "./RemoteShellContent.js";
|
|
4
5
|
import { RemoteShellPanel } from "./RemoteShellPanel.js";
|
|
5
|
-
export { RemoteShell, RemoteShellBreadcrumb, RemoteShellContent, RemoteShellPanel };
|
|
6
|
+
export { RemoteShell, RemoteShellBreadcrumb, RemoteShellContent, RemoteShellPanel, findFirstLinkPath, pushPathname, useLocationPathname, useRemoteShellContext };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BreadcrumbSegment, NavConfig, NavConfigDrill, NavStackEntry } from './types';
|
|
2
|
-
export interface
|
|
2
|
+
export interface RemoteShellContextValue {
|
|
3
3
|
config: NavConfig;
|
|
4
4
|
pathname: string;
|
|
5
5
|
navStack: NavStackEntry[];
|
|
@@ -18,5 +18,5 @@ export interface ProductNavContextValue {
|
|
|
18
18
|
/** Navigate to an absolute href (used by breadcrumbs) */
|
|
19
19
|
navigateTo: (href: string) => void;
|
|
20
20
|
}
|
|
21
|
-
export declare const
|
|
22
|
-
export declare function
|
|
21
|
+
export declare const RemoteShellContextProvider: import("react").Provider<RemoteShellContextValue | null>;
|
|
22
|
+
export declare function useRemoteShellContext(): RemoteShellContextValue;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
const RemoteShellCtx = createContext(null);
|
|
3
|
+
const RemoteShellContextProvider = RemoteShellCtx.Provider;
|
|
4
|
+
function useRemoteShellContext() {
|
|
5
|
+
const ctx = useContext(RemoteShellCtx);
|
|
6
|
+
if (!ctx) throw new Error('useRemoteShellContext must be used within a RemoteShell with a config prop');
|
|
7
|
+
return ctx;
|
|
8
|
+
}
|
|
9
|
+
export { RemoteShellContextProvider, useRemoteShellContext };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { type MatchNavResult, matchNav } from './matchNav';
|
|
2
|
+
export { findDrillNode, findFirstLinkPath } from './navUtils';
|
|
3
|
+
export { RemoteShellContextProvider, type RemoteShellContextValue, useRemoteShellContext, } from './RemoteShellContext';
|
|
4
|
+
export type { BreadcrumbSegment, NavConfig, NavConfigDrill, NavConfigGroup, NavConfigHeaderAction, NavConfigLink, NavConfigNode, NavConfigSectionHeader, NavStackEntry, } from './types';
|
|
5
|
+
export { pushPathname, useLocationPathname } from './useLocationPathname';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { matchNav } from "./matchNav.js";
|
|
2
|
+
import { findDrillNode, findFirstLinkPath } from "./navUtils.js";
|
|
3
|
+
import { RemoteShellContextProvider, useRemoteShellContext } from "./RemoteShellContext.js";
|
|
4
|
+
import { pushPathname, useLocationPathname } from "./useLocationPathname.js";
|
|
5
|
+
export { RemoteShellContextProvider, findDrillNode, findFirstLinkPath, matchNav, pushPathname, useLocationPathname, useRemoteShellContext };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ComponentType } from 'react';
|
|
2
|
-
import type { SvgIconProps } from '
|
|
2
|
+
import type { SvgIconProps } from '../../../icons/SvgIcon';
|
|
3
3
|
export interface NavConfigHeaderAction {
|
|
4
4
|
icon: ComponentType<SvgIconProps>;
|
|
5
5
|
label: string;
|
|
@@ -35,7 +35,6 @@ export interface NavConfigDrill {
|
|
|
35
35
|
label: string;
|
|
36
36
|
description?: string;
|
|
37
37
|
}[];
|
|
38
|
-
/** Render a visual divider after this item */
|
|
39
38
|
dividerAfter?: boolean;
|
|
40
39
|
}
|
|
41
40
|
export interface NavConfigGroup {
|
|
@@ -45,7 +44,6 @@ export interface NavConfigGroup {
|
|
|
45
44
|
children: NavConfigNode[];
|
|
46
45
|
icon?: ComponentType<SvgIconProps>;
|
|
47
46
|
defaultExpanded?: boolean;
|
|
48
|
-
/** Render a visual divider after this item */
|
|
49
47
|
dividerAfter?: boolean;
|
|
50
48
|
}
|
|
51
49
|
export interface NavConfigSectionHeader {
|
package/dist/index.d.ts
CHANGED
|
@@ -47,10 +47,9 @@ export { OverflowTooltip, OverflowTooltipContent, type OverflowTooltipContentPro
|
|
|
47
47
|
export { Page, PageActions, type PageActionsProps, PageContent, type PageContentProps, PageHeader, type PageHeaderProps, type PageHostContextValue, PageHostProvider, type PageLayoutOptions, type PageProps, PageTitle, type PageTitleProps, usePageHost, } from './components/Page';
|
|
48
48
|
export { type CopyFormatData, formatAsFilter, ParameterPath, type ParameterPathProps, } from './components/ParameterPath';
|
|
49
49
|
export { Popover, PopoverContent, PopoverTrigger } from './components/Popover';
|
|
50
|
-
export { type BreadcrumbSegment, findDrillNode, findFirstLinkPath, type MatchNavResult, matchNav, type NavConfig, type NavConfigDrill, type NavConfigGroup, type NavConfigLink, type NavConfigNode, NavPanelSkeleton, type NavPanelSkeletonProps, type NavStackEntry, ProductNav, ProductNavBreadcrumbs, type ProductNavContextValue, ProductNavPanel, type ProductNavProps, type UseProductNavResult, useProductNav, useProductNavContext, } from './components/ProductNav';
|
|
51
50
|
export { Progress, type ProgressColor, type ProgressProps, } from './components/Progress';
|
|
52
51
|
export { Radio, RadioDescription, type RadioDescriptionProps, RadioGroup, type RadioGroupProps, RadioIndicator, RadioLabel, type RadioLabelProps, type RadioProps, } from './components/Radio';
|
|
53
|
-
export { RemoteShell, RemoteShellBreadcrumb, type RemoteShellBreadcrumbProps, RemoteShellContent, type RemoteShellContentProps, RemoteShellPanel, type RemoteShellPanelProps, type RemoteShellProps, } from './components/RemoteShell';
|
|
52
|
+
export { type BreadcrumbSegment, findFirstLinkPath, type NavConfig, type NavConfigDrill, type NavConfigGroup, type NavConfigLink, type NavConfigNode, type NavStackEntry, pushPathname, RemoteShell, RemoteShellBreadcrumb, type RemoteShellBreadcrumbProps, RemoteShellContent, type RemoteShellContentProps, type RemoteShellContextValue, RemoteShellPanel, type RemoteShellPanelProps, type RemoteShellProps, useLocationPathname, useRemoteShellContext, } from './components/RemoteShell';
|
|
54
53
|
export { getResponseCodeCategory, RESPONSE_CODE_COLOR, ResponseCode, type ResponseCodeCategory, type ResponseCodeProps, } from './components/ResponseCode';
|
|
55
54
|
export { ScrollArea, ScrollAreaContent, type ScrollAreaContentProps, ScrollAreaCorner, type ScrollAreaProps, ScrollAreaScrollbar, type ScrollAreaScrollbarProps, ScrollAreaViewport, type ScrollAreaViewportProps, } from './components/ScrollArea';
|
|
56
55
|
export { SegmentedControl, SegmentedControlButton, type SegmentedControlButtonProps, SegmentedControlItem, type SegmentedControlItemProps, type SegmentedControlProps, SegmentedControlSeparator, type SegmentedControlSeparatorProps, } from './components/SegmentedControl';
|