@wallarm-org/design-system 0.50.1-rc-feature-shell.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.
Files changed (51) hide show
  1. package/dist/components/AppShell/story-content/_storyConfigRenderer.d.ts +1 -1
  2. package/dist/components/AppShell/story-content/_storyConfigRenderer.js +15 -29
  3. package/dist/components/AppShell/story-content/_storyLib.js +1 -1
  4. package/dist/components/AppShell/story-content/_storyNavConfigs.d.ts +1 -1
  5. package/dist/components/NavPanel/NavPanelHeader.js +1 -1
  6. package/dist/components/Page/PageContent.js +1 -1
  7. package/dist/components/Page/PageHeader.js +1 -1
  8. package/dist/components/{ProductNav → RemoteShell}/HeaderActions.d.ts +1 -1
  9. package/dist/components/{ProductNav → RemoteShell}/NavItemsList.d.ts +1 -1
  10. package/dist/components/RemoteShell/NavPanelContent.d.ts +6 -0
  11. package/dist/components/RemoteShell/NavPanelContent.js +64 -0
  12. package/dist/components/RemoteShell/RemoteShell.d.ts +7 -0
  13. package/dist/components/RemoteShell/RemoteShell.js +112 -9
  14. package/dist/components/RemoteShell/RemoteShellBreadcrumb.js +39 -4
  15. package/dist/components/RemoteShell/RemoteShellContent.d.ts +1 -0
  16. package/dist/components/RemoteShell/RemoteShellContent.js +7 -3
  17. package/dist/components/RemoteShell/RemoteShellPanel.d.ts +4 -2
  18. package/dist/components/RemoteShell/RemoteShellPanel.js +76 -3
  19. package/dist/components/RemoteShell/index.d.ts +2 -0
  20. package/dist/components/RemoteShell/index.js +2 -1
  21. package/dist/components/{ProductNav/ProductNavContext.d.ts → RemoteShell/model/RemoteShellContext.d.ts} +3 -3
  22. package/dist/components/RemoteShell/model/RemoteShellContext.js +9 -0
  23. package/dist/components/RemoteShell/model/index.d.ts +5 -0
  24. package/dist/components/RemoteShell/model/index.js +5 -0
  25. package/dist/components/{ProductNav → RemoteShell/model}/types.d.ts +1 -3
  26. package/dist/index.d.ts +1 -2
  27. package/dist/index.js +2 -3
  28. package/dist/metadata/components.json +35 -303
  29. package/package.json +1 -1
  30. package/dist/components/ProductNav/ProductNav.d.ts +0 -13
  31. package/dist/components/ProductNav/ProductNav.js +0 -109
  32. package/dist/components/ProductNav/ProductNavBreadcrumbs.d.ts +0 -2
  33. package/dist/components/ProductNav/ProductNavBreadcrumbs.js +0 -38
  34. package/dist/components/ProductNav/ProductNavContext.js +0 -9
  35. package/dist/components/ProductNav/ProductNavPanel.d.ts +0 -6
  36. package/dist/components/ProductNav/ProductNavPanel.js +0 -107
  37. package/dist/components/ProductNav/index.d.ts +0 -11
  38. package/dist/components/ProductNav/index.js +0 -10
  39. package/dist/components/ProductNav/useProductNav.d.ts +0 -16
  40. package/dist/components/ProductNav/useProductNav.js +0 -19
  41. /package/dist/components/{ProductNav → RemoteShell}/HeaderActions.js +0 -0
  42. /package/dist/components/{ProductNav → RemoteShell}/NavItemsList.js +0 -0
  43. /package/dist/components/{ProductNav → RemoteShell/model}/matchNav.d.ts +0 -0
  44. /package/dist/components/{ProductNav → RemoteShell/model}/matchNav.js +0 -0
  45. /package/dist/components/{ProductNav → RemoteShell/model}/navUtils.d.ts +0 -0
  46. /package/dist/components/{ProductNav → RemoteShell/model}/navUtils.js +0 -0
  47. /package/dist/components/{ProductNav → RemoteShell/model}/types.js +0 -0
  48. /package/dist/components/{ProductNav → RemoteShell/model}/useDrillTransition.d.ts +0 -0
  49. /package/dist/components/{ProductNav → RemoteShell/model}/useDrillTransition.js +0 -0
  50. /package/dist/components/{ProductNav → RemoteShell/model}/useLocationPathname.d.ts +0 -0
  51. /package/dist/components/{ProductNav → RemoteShell/model}/useLocationPathname.js +0 -0
@@ -1,4 +1,4 @@
1
- import { type NavConfig } from '../../ProductNav';
1
+ import { type NavConfig } from '../../RemoteShell';
2
2
  import { type Product } from './_storyLib';
3
3
  export interface ConfigRemoteProps {
4
4
  config: NavConfig;
@@ -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 { NavPanelSkeleton, ProductNav, ProductNavBreadcrumbs, ProductNavPanel, useProductNavContext } from "../../ProductNav/index.js";
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 } = useProductNavContext();
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
- if (loading) return /*#__PURE__*/ jsxs(RemoteShell, {
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(RemoteShell, {
48
+ children: loading ? /*#__PURE__*/ jsxs(Fragment, {
68
49
  children: [
69
50
  /*#__PURE__*/ jsx(RemoteShellPanel, {
70
- children: /*#__PURE__*/ jsx(ProductNavPanel, {
71
- resizable: true
72
- })
51
+ isLoading: true
73
52
  }),
74
- /*#__PURE__*/ jsx(RemoteShellBreadcrumb, {
75
- children: /*#__PURE__*/ jsx(ProductNavBreadcrumbs, {})
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 "../../ProductNav/index.js";
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',
@@ -1,4 +1,4 @@
1
- import type { NavConfig } from '../../ProductNav';
1
+ import type { NavConfig } from '../../RemoteShell';
2
2
  export declare const edgeNavConfig: NavConfig;
3
3
  export declare const aiHypervisorNavConfig: NavConfig;
4
4
  export declare const infraDiscoveryNavConfig: NavConfig;
@@ -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-24 py-16', className),
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-24 py-16 gap-12', sticky && 'sticky top-0 z-10 bg-bg-primary', className),
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
  };
@@ -1,5 +1,5 @@
1
1
  import type { FC } from 'react';
2
- import type { NavConfigHeaderAction } from './types';
2
+ import type { NavConfigHeaderAction } from './model';
3
3
  export type HeaderActionsProps = {
4
4
  actions: NavConfigHeaderAction[];
5
5
  };
@@ -1,5 +1,5 @@
1
1
  import type { FC } from 'react';
2
- import type { NavConfigDrill, NavConfigNode } from './types';
2
+ import type { NavConfigDrill, NavConfigNode } from './model/types';
3
3
  export type NavItemsListProps = {
4
4
  items: NavConfigNode[];
5
5
  activeItemId: string | null;
@@ -0,0 +1,6 @@
1
+ import type { FC } from 'react';
2
+ interface NavPanelContentProps {
3
+ level: number;
4
+ }
5
+ export declare const NavPanelContent: FC<NavPanelContentProps>;
6
+ export {};
@@ -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
- const RemoteShell = ({ ref, className, children, 'data-testid': testId, ...props })=>/*#__PURE__*/ jsx(TestIdProvider, {
5
- value: testId,
6
- children: /*#__PURE__*/ jsx("div", {
7
- ...props,
8
- ref: ref,
9
- "data-slot": "remote-shell",
10
- "data-testid": testId,
11
- 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),
12
- children: children
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
- return /*#__PURE__*/ jsx("div", {
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-24 py-8', className),
12
- children: 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
- const RemoteShellContent = ({ ref, className, children, ...props })=>{
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 px-24 py-16 [scrollbar-width:thin]', className),
12
- children: 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, ReactNode, Ref } from 'react';
1
+ import type { FC, HTMLAttributes, Ref } from 'react';
2
2
  export interface RemoteShellPanelProps extends HTMLAttributes<HTMLDivElement> {
3
3
  ref?: Ref<HTMLDivElement>;
4
- children?: ReactNode;
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
- const RemoteShellPanel = ({ ref, className, children, ...props })=>{
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: 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 ProductNavContextValue {
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 ProductNavContextProvider: import("react").Provider<ProductNavContextValue | null>;
22
- export declare function useProductNavContext(): ProductNavContextValue;
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 '../../icons/SvgIcon';
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';