@wallarm-org/design-system 0.50.2 → 0.51.0-rc-feature-AS-1026.2

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 (84) hide show
  1. package/dist/components/AppShell/story-content/_storyConfigRenderer.d.ts +1 -1
  2. package/dist/components/AppShell/story-content/_storyConfigRenderer.js +29 -15
  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/AppShell/story-content/_storyNavConfigs.js +0 -5
  6. package/dist/components/NavPanel/NavPanelHeader.js +1 -1
  7. package/dist/components/Page/PageContent.js +1 -1
  8. package/dist/components/Page/PageHeader.js +1 -1
  9. package/dist/components/{RemoteShell → ProductNav}/HeaderActions.d.ts +1 -1
  10. package/dist/components/{RemoteShell → ProductNav}/NavItemsList.d.ts +1 -1
  11. package/dist/components/ProductNav/ProductNav.d.ts +13 -0
  12. package/dist/components/ProductNav/ProductNav.js +109 -0
  13. package/dist/components/ProductNav/ProductNavBreadcrumbs.d.ts +2 -0
  14. package/dist/components/ProductNav/ProductNavBreadcrumbs.js +38 -0
  15. package/dist/components/{RemoteShell/model/RemoteShellContext.d.ts → ProductNav/ProductNavContext.d.ts} +3 -3
  16. package/dist/components/ProductNav/ProductNavContext.js +9 -0
  17. package/dist/components/ProductNav/ProductNavPanel.d.ts +6 -0
  18. package/dist/components/ProductNav/ProductNavPanel.js +107 -0
  19. package/dist/components/ProductNav/index.d.ts +11 -0
  20. package/dist/components/ProductNav/index.js +10 -0
  21. package/dist/components/{RemoteShell/model → ProductNav}/matchNav.js +1 -1
  22. package/dist/components/{RemoteShell/model → ProductNav}/types.d.ts +3 -2
  23. package/dist/components/ProductNav/useProductNav.d.ts +16 -0
  24. package/dist/components/ProductNav/useProductNav.js +19 -0
  25. package/dist/components/RemoteShell/RemoteShell.d.ts +0 -7
  26. package/dist/components/RemoteShell/RemoteShell.js +9 -109
  27. package/dist/components/RemoteShell/RemoteShellBreadcrumb.js +4 -39
  28. package/dist/components/RemoteShell/RemoteShellContent.d.ts +0 -1
  29. package/dist/components/RemoteShell/RemoteShellContent.js +3 -7
  30. package/dist/components/RemoteShell/RemoteShellPanel.d.ts +2 -4
  31. package/dist/components/RemoteShell/RemoteShellPanel.js +3 -76
  32. package/dist/components/RemoteShell/index.d.ts +0 -2
  33. package/dist/components/RemoteShell/index.js +1 -2
  34. package/dist/components/Table/TableBody/TableBodyVirtualizedContainer.js +5 -2
  35. package/dist/components/Table/TableBody/TableBodyVirtualizedWindow.js +5 -2
  36. package/dist/components/Table/TableBody/useResetVirtualizerOnDataChange.d.ts +3 -3
  37. package/dist/components/Table/TableBody/useResetVirtualizerOnDataChange.js +8 -6
  38. package/dist/components/Table/TableContext/TableProvider.js +7 -1
  39. package/dist/components/Table/TableContext/types.d.ts +3 -0
  40. package/dist/components/Table/TableInner/TableInnerContainer.js +9 -4
  41. package/dist/components/Table/TableInner/TableInnerWindow.js +9 -4
  42. package/dist/components/Table/hooks/index.d.ts +1 -1
  43. package/dist/components/Table/hooks/index.js +2 -2
  44. package/dist/components/Table/hooks/infiniteScroll/index.d.ts +1 -0
  45. package/dist/components/Table/hooks/infiniteScroll/index.js +2 -0
  46. package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.d.ts +18 -0
  47. package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.js +35 -0
  48. package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.d.ts +16 -0
  49. package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.js +28 -0
  50. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.d.ts +22 -0
  51. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.js +39 -0
  52. package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.d.ts +20 -0
  53. package/dist/components/Table/hooks/{useEndReached.js → infiniteScroll/useScrollEdge.js} +15 -11
  54. package/dist/components/Table/lib/constants.d.ts +3 -0
  55. package/dist/components/Table/lib/constants.js +3 -1
  56. package/dist/components/Table/lib/detectDataChange.d.ts +4 -0
  57. package/dist/components/Table/lib/detectDataChange.js +7 -0
  58. package/dist/components/Table/lib/getRowKey.d.ts +4 -0
  59. package/dist/components/Table/lib/getRowKey.js +2 -0
  60. package/dist/components/Table/lib/index.d.ts +3 -1
  61. package/dist/components/Table/lib/index.js +4 -2
  62. package/dist/components/Table/mocks.d.ts +13 -0
  63. package/dist/components/Table/mocks.js +59 -1
  64. package/dist/components/Table/types.d.ts +11 -1
  65. package/dist/index.d.ts +2 -1
  66. package/dist/index.js +3 -2
  67. package/dist/metadata/components.json +312 -34
  68. package/package.json +1 -1
  69. package/dist/components/RemoteShell/NavPanelContent.d.ts +0 -6
  70. package/dist/components/RemoteShell/NavPanelContent.js +0 -65
  71. package/dist/components/RemoteShell/model/RemoteShellContext.js +0 -9
  72. package/dist/components/RemoteShell/model/index.d.ts +0 -5
  73. package/dist/components/RemoteShell/model/index.js +0 -5
  74. package/dist/components/Table/hooks/useEndReached.d.ts +0 -19
  75. /package/dist/components/{RemoteShell → ProductNav}/HeaderActions.js +0 -0
  76. /package/dist/components/{RemoteShell → ProductNav}/NavItemsList.js +0 -0
  77. /package/dist/components/{RemoteShell/model → ProductNav}/matchNav.d.ts +0 -0
  78. /package/dist/components/{RemoteShell/model → ProductNav}/navUtils.d.ts +0 -0
  79. /package/dist/components/{RemoteShell/model → ProductNav}/navUtils.js +0 -0
  80. /package/dist/components/{RemoteShell/model → ProductNav}/types.js +0 -0
  81. /package/dist/components/{RemoteShell/model → ProductNav}/useDrillTransition.d.ts +0 -0
  82. /package/dist/components/{RemoteShell/model → ProductNav}/useDrillTransition.js +0 -0
  83. /package/dist/components/{RemoteShell/model → ProductNav}/useLocationPathname.d.ts +0 -0
  84. /package/dist/components/{RemoteShell/model → ProductNav}/useLocationPathname.js +0 -0
@@ -1,4 +1,4 @@
1
- import { type NavConfig } from '../../RemoteShell';
1
+ import { type NavConfig } from '../../ProductNav';
2
2
  import { type Product } from './_storyLib';
3
3
  export interface ConfigRemoteProps {
4
4
  config: NavConfig;
@@ -1,11 +1,13 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
+ import { NavPanel, NavPanelHeader } from "../../NavPanel/index.js";
3
4
  import { Page, PageContent, PageHeader, PageTitle } from "../../Page/index.js";
4
- import { RemoteShell, RemoteShellBreadcrumb, RemoteShellContent, RemoteShellPanel, useRemoteShellContext } from "../../RemoteShell/index.js";
5
+ import { NavPanelSkeleton, ProductNav, ProductNavBreadcrumbs, ProductNavPanel, useProductNavContext } from "../../ProductNav/index.js";
6
+ import { RemoteShell, RemoteShellBreadcrumb, RemoteShellContent, RemoteShellPanel } from "../../RemoteShell/index.js";
5
7
  import { HomeContent } from "./_storyHomeContent.js";
6
8
  import { PRODUCT_CONFIGS } from "./_storyLib.js";
7
9
  const RemotePageContent = ()=>{
8
- const { breadcrumbSegments } = useRemoteShellContext();
10
+ const { breadcrumbSegments } = useProductNavContext();
9
11
  const lastSegment = breadcrumbSegments[breadcrumbSegments.length - 1];
10
12
  const pageTitle = lastSegment?.label ?? '';
11
13
  const fullPath = breadcrumbSegments.map((s)=>s.label).join(' / ');
@@ -42,24 +44,36 @@ const ConfigRemote = ({ config, basePath })=>{
42
44
  }, [
43
45
  config.productLabel
44
46
  ]);
45
- return /*#__PURE__*/ jsx(RemoteShell, {
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, {
46
65
  config: config,
47
66
  basePath: basePath,
48
- children: loading ? /*#__PURE__*/ jsxs(Fragment, {
67
+ children: /*#__PURE__*/ jsxs(RemoteShell, {
49
68
  children: [
50
69
  /*#__PURE__*/ jsx(RemoteShellPanel, {
51
- isLoading: true
70
+ children: /*#__PURE__*/ jsx(ProductNavPanel, {
71
+ resizable: true
72
+ })
52
73
  }),
53
- /*#__PURE__*/ jsx(RemoteShellContent, {
54
- isLoading: true
55
- })
56
- ]
57
- }) : /*#__PURE__*/ jsxs(Fragment, {
58
- children: [
59
- /*#__PURE__*/ jsx(RemoteShellPanel, {
60
- resizable: true
74
+ /*#__PURE__*/ jsx(RemoteShellBreadcrumb, {
75
+ children: /*#__PURE__*/ jsx(ProductNavBreadcrumbs, {})
61
76
  }),
62
- /*#__PURE__*/ jsx(RemoteShellBreadcrumb, {}),
63
77
  /*#__PURE__*/ jsx(RemoteShellContent, {
64
78
  children: /*#__PURE__*/ jsx(RemotePageContent, {})
65
79
  })
@@ -1,4 +1,4 @@
1
- import { findFirstLinkPath, pushPathname } from "../../RemoteShell/index.js";
1
+ import { findFirstLinkPath, pushPathname } from "../../ProductNav/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 '../../RemoteShell';
1
+ import type { NavConfig } from '../../ProductNav';
2
2
  export declare const edgeNavConfig: NavConfig;
3
3
  export declare const aiHypervisorNavConfig: NavConfig;
4
4
  export declare const infraDiscoveryNavConfig: NavConfig;
@@ -1,7 +1,6 @@
1
1
  import { CircleDashed, Filter, Plus } from "../../../icons/index.js";
2
2
  const edgeNavConfig = {
3
3
  productLabel: 'Edge',
4
- productPath: '/edge',
5
4
  headerActions: [
6
5
  {
7
6
  icon: Filter,
@@ -341,7 +340,6 @@ const edgeNavConfig = {
341
340
  };
342
341
  const aiHypervisorNavConfig = {
343
342
  productLabel: 'AI Hypervisor',
344
- productPath: '/ai-hypervisor',
345
343
  items: [
346
344
  {
347
345
  type: 'link',
@@ -456,7 +454,6 @@ const aiHypervisorNavConfig = {
456
454
  };
457
455
  const infraDiscoveryNavConfig = {
458
456
  productLabel: 'Infra Discovery',
459
- productPath: '/infra-discovery',
460
457
  headerActions: [
461
458
  {
462
459
  icon: Filter,
@@ -557,7 +554,6 @@ const infraDiscoveryNavConfig = {
557
554
  };
558
555
  const securityTestingNavConfig = {
559
556
  productLabel: 'Security Testing',
560
- productPath: '/security-testing',
561
557
  items: [
562
558
  {
563
559
  type: 'link',
@@ -631,7 +627,6 @@ const securityTestingNavConfig = {
631
627
  };
632
628
  const settingsNavConfig = {
633
629
  productLabel: 'Settings',
634
- productPath: '/settings',
635
630
  items: [
636
631
  {
637
632
  type: 'link',
@@ -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 bg-bg-surface-2', className),
12
+ className: cn('sticky top-0 z-10 flex shrink-0 items-center p-4', 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-16', className),
11
+ className: cn('flex-1 min-h-0 overflow-auto px-24 py-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-16 pb-16 gap-12', sticky && 'sticky top-0 z-10 bg-bg-surface-2', className),
11
+ className: cn('flex items-center px-24 py-16 gap-12', sticky && 'sticky top-0 z-10 bg-bg-primary', 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 './model';
2
+ import type { NavConfigHeaderAction } from './types';
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 './model/types';
2
+ import type { NavConfigDrill, NavConfigNode } from './types';
3
3
  export type NavItemsListProps = {
4
4
  items: NavConfigNode[];
5
5
  activeItemId: string | null;
@@ -0,0 +1,13 @@
1
+ import { type FC, type ReactNode } from 'react';
2
+ import type { NavConfig } from './types';
3
+ export interface ProductNavProps {
4
+ config: NavConfig;
5
+ /** URL prefix stripped before matching and prepended when navigating.
6
+ * Example: `"/edge"` turns URL `/edge/overview` into effective pathname `/overview`. */
7
+ basePath?: string;
8
+ /** Custom navigation handler for router integration (React Router, Next.js, etc.).
9
+ * Default: uses history.pushState to update the URL directly. */
10
+ onNavigate?: (pathname: string) => void;
11
+ children: ReactNode;
12
+ }
13
+ export declare const ProductNav: FC<ProductNavProps>;
@@ -0,0 +1,109 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { matchNav } from "./matchNav.js";
4
+ import { findFirstLinkPath } from "./navUtils.js";
5
+ import { ProductNavContextProvider } from "./ProductNavContext.js";
6
+ import { pushPathname, useLocationPathname } from "./useLocationPathname.js";
7
+ const ProductNav = ({ config, basePath, onNavigate, children })=>{
8
+ const fullPathname = useLocationPathname();
9
+ const pathname = basePath && fullPathname.startsWith(basePath) ? fullPathname.slice(basePath.length) || '/' : fullPathname;
10
+ const setPathname = useCallback((next)=>{
11
+ const fullPath = basePath ? `${basePath}${next}` : next;
12
+ if (onNavigate) onNavigate(fullPath);
13
+ else pushPathname(fullPath);
14
+ }, [
15
+ basePath,
16
+ onNavigate
17
+ ]);
18
+ const { navStack, breadcrumbSegments, activeItemId } = useMemo(()=>matchNav(pathname, config), [
19
+ pathname,
20
+ config
21
+ ]);
22
+ const urlDrillLevel = navStack.length - 1;
23
+ const [visualDrillLevel, setVisualDrillLevel] = useState(null);
24
+ useEffect(()=>{
25
+ setVisualDrillLevel(null);
26
+ }, [
27
+ pathname
28
+ ]);
29
+ const effectiveDrillLevel = visualDrillLevel ?? urlDrillLevel;
30
+ const effectiveActiveItemId = effectiveDrillLevel < urlDrillLevel ? navStack[effectiveDrillLevel]?.activeItemId ?? activeItemId : activeItemId;
31
+ const navigate = useCallback((path)=>{
32
+ setVisualDrillLevel(null);
33
+ const segments = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
34
+ const prefixSegments = segments.slice(0, 2 * effectiveDrillLevel);
35
+ setPathname(`/${[
36
+ ...prefixSegments,
37
+ path
38
+ ].join('/')}`);
39
+ }, [
40
+ effectiveDrillLevel,
41
+ pathname,
42
+ setPathname
43
+ ]);
44
+ const drillInto = useCallback((drill)=>{
45
+ setVisualDrillLevel(null);
46
+ const segments = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
47
+ const prefixSegments = segments.slice(0, 2 * effectiveDrillLevel);
48
+ const defaultEntity = drill.entities?.[0]?.id ?? 'default';
49
+ const firstChildPath = findFirstLinkPath(drill.children) ?? '';
50
+ setPathname(`/${[
51
+ ...prefixSegments,
52
+ drill.path,
53
+ defaultEntity,
54
+ firstChildPath
55
+ ].join('/')}`);
56
+ }, [
57
+ effectiveDrillLevel,
58
+ pathname,
59
+ setPathname
60
+ ]);
61
+ const goBack = useCallback(()=>{
62
+ setVisualDrillLevel((prev)=>{
63
+ const current = prev ?? urlDrillLevel;
64
+ return Math.max(current - 1, 0);
65
+ });
66
+ }, [
67
+ urlDrillLevel
68
+ ]);
69
+ const navigateTo = useCallback((href)=>{
70
+ setVisualDrillLevel(null);
71
+ if ('/' === href) {
72
+ const firstPath = findFirstLinkPath(config.items) ?? '';
73
+ setPathname(`/${firstPath}`);
74
+ } else setPathname(href);
75
+ }, [
76
+ config.items,
77
+ setPathname
78
+ ]);
79
+ const navCtxValue = useMemo(()=>({
80
+ config,
81
+ pathname,
82
+ navStack,
83
+ breadcrumbSegments,
84
+ activeItemId,
85
+ drillLevel: effectiveDrillLevel,
86
+ effectiveActiveItemId,
87
+ navigate,
88
+ drillInto,
89
+ goBack,
90
+ navigateTo
91
+ }), [
92
+ config,
93
+ pathname,
94
+ navStack,
95
+ breadcrumbSegments,
96
+ activeItemId,
97
+ effectiveDrillLevel,
98
+ effectiveActiveItemId,
99
+ navigate,
100
+ drillInto,
101
+ goBack,
102
+ navigateTo
103
+ ]);
104
+ return /*#__PURE__*/ jsx(ProductNavContextProvider, {
105
+ value: navCtxValue,
106
+ children: children
107
+ });
108
+ };
109
+ export { ProductNav };
@@ -0,0 +1,2 @@
1
+ import type { FC } from 'react';
2
+ export declare const ProductNavBreadcrumbs: FC;
@@ -0,0 +1,38 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Breadcrumbs, BreadcrumbsItem, BreadcrumbsScopeSwitcher } from "../Breadcrumbs/index.js";
3
+ import { useProductNavContext } from "./ProductNavContext.js";
4
+ const ProductNavBreadcrumbs = ()=>{
5
+ const { breadcrumbSegments, navigateTo } = useProductNavContext();
6
+ return /*#__PURE__*/ jsx(Breadcrumbs, {
7
+ "data-slot": "nav-breadcrumbs",
8
+ children: breadcrumbSegments.map((segment, i)=>{
9
+ const isLast = i === breadcrumbSegments.length - 1;
10
+ if ('scope-switcher' === segment.type) {
11
+ if (segment.scopeItems?.length && segment.paramValue) return /*#__PURE__*/ jsx(BreadcrumbsScopeSwitcher, {
12
+ value: segment.paramValue,
13
+ items: segment.scopeItems,
14
+ onSelect: (item)=>navigateTo?.(item.href),
15
+ children: segment.label
16
+ }, i);
17
+ return /*#__PURE__*/ jsx(BreadcrumbsItem, {
18
+ children: segment.label
19
+ }, i);
20
+ }
21
+ if ('link' === segment.type && !isLast) return /*#__PURE__*/ jsx(BreadcrumbsItem, {
22
+ href: segment.href,
23
+ onClick: (e)=>{
24
+ if (navigateTo && segment.href) {
25
+ e.preventDefault();
26
+ navigateTo(segment.href);
27
+ }
28
+ },
29
+ children: segment.label
30
+ }, i);
31
+ return /*#__PURE__*/ jsx(BreadcrumbsItem, {
32
+ children: segment.label
33
+ }, i);
34
+ })
35
+ });
36
+ };
37
+ ProductNavBreadcrumbs.displayName = 'ProductNavBreadcrumbs';
38
+ export { ProductNavBreadcrumbs };
@@ -1,5 +1,5 @@
1
1
  import type { BreadcrumbSegment, NavConfig, NavConfigDrill, NavStackEntry } from './types';
2
- export interface RemoteShellContextValue {
2
+ export interface ProductNavContextValue {
3
3
  config: NavConfig;
4
4
  pathname: string;
5
5
  navStack: NavStackEntry[];
@@ -18,5 +18,5 @@ export interface RemoteShellContextValue {
18
18
  /** Navigate to an absolute href (used by breadcrumbs) */
19
19
  navigateTo: (href: string) => void;
20
20
  }
21
- export declare const RemoteShellContextProvider: import("react").Provider<RemoteShellContextValue | null>;
22
- export declare function useRemoteShellContext(): RemoteShellContextValue;
21
+ export declare const ProductNavContextProvider: import("react").Provider<ProductNavContextValue | null>;
22
+ export declare function useProductNavContext(): ProductNavContextValue;
@@ -0,0 +1,9 @@
1
+ import { createContext, useContext } from "react";
2
+ const ProductNavCtx = createContext(null);
3
+ const ProductNavContextProvider = ProductNavCtx.Provider;
4
+ function useProductNavContext() {
5
+ const ctx = useContext(ProductNavCtx);
6
+ if (!ctx) throw new Error('useProductNavContext must be used within a ProductNav provider');
7
+ return ctx;
8
+ }
9
+ export { ProductNavContextProvider, useProductNavContext };
@@ -0,0 +1,6 @@
1
+ import type { FC } from 'react';
2
+ type ProductNavPanelProps = {
3
+ resizable?: boolean;
4
+ };
5
+ export declare const ProductNavPanel: FC<ProductNavPanelProps>;
6
+ export {};
@@ -0,0 +1,107 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { NavPanel, NavPanelBack, NavPanelDivider, NavPanelHeader } from "../NavPanel/index.js";
3
+ import { Text } from "../Text/index.js";
4
+ import { HeaderActions } from "./HeaderActions.js";
5
+ import { NavItemsList } from "./NavItemsList.js";
6
+ import { findDrillNode } from "./navUtils.js";
7
+ import { useProductNavContext } from "./ProductNavContext.js";
8
+ import { DRILL_ANIMATION_DURATION, DRILL_ANIMATION_EASING, useDrillTransition } from "./useDrillTransition.js";
9
+ const ProductNavPanel = ({ resizable })=>{
10
+ const { config, navStack, effectiveActiveItemId, navigate, drillInto, goBack, drillLevel } = useProductNavContext();
11
+ const { transition, clearTransition } = useDrillTransition(drillLevel);
12
+ const hasHeaderActions = !!config.headerActions?.length;
13
+ const renderContent = (level)=>{
14
+ const entry = navStack[Math.min(level, navStack.length - 1)];
15
+ if (0 === level) return /*#__PURE__*/ jsxs(Fragment, {
16
+ children: [
17
+ hasHeaderActions ? /*#__PURE__*/ jsxs("div", {
18
+ className: "sticky top-0 z-10 flex shrink-0 items-center justify-between p-4",
19
+ children: [
20
+ /*#__PURE__*/ jsx(Text, {
21
+ size: "sm",
22
+ weight: "medium",
23
+ children: config.productLabel
24
+ }),
25
+ /*#__PURE__*/ jsx(HeaderActions, {
26
+ actions: config.headerActions
27
+ })
28
+ ]
29
+ }) : /*#__PURE__*/ jsx(NavPanelHeader, {
30
+ children: config.productLabel
31
+ }),
32
+ /*#__PURE__*/ jsx(NavItemsList, {
33
+ items: config.items,
34
+ activeItemId: effectiveActiveItemId,
35
+ onNavigate: navigate,
36
+ onDrillClick: drillInto
37
+ })
38
+ ]
39
+ });
40
+ const parentEntry = navStack[level - 1];
41
+ const drillNode = findDrillNode(parentEntry.items, parentEntry.activeItemId);
42
+ const backLabel = drillNode?.label ?? 'Back';
43
+ return /*#__PURE__*/ jsxs(Fragment, {
44
+ children: [
45
+ /*#__PURE__*/ jsxs("div", {
46
+ className: "sticky top-0 z-10 flex flex-col gap-2 bg-bg-surface-1",
47
+ children: [
48
+ /*#__PURE__*/ jsx(NavPanelHeader, {
49
+ children: entry.title
50
+ }),
51
+ /*#__PURE__*/ jsx(NavPanelBack, {
52
+ onClick: goBack,
53
+ children: backLabel
54
+ }),
55
+ /*#__PURE__*/ jsx(NavPanelDivider, {})
56
+ ]
57
+ }),
58
+ /*#__PURE__*/ jsx(NavItemsList, {
59
+ items: entry.items,
60
+ activeItemId: effectiveActiveItemId,
61
+ onNavigate: navigate,
62
+ onDrillClick: drillInto
63
+ })
64
+ ]
65
+ });
66
+ };
67
+ if (transition) {
68
+ const isForward = 'forward' === transition.direction;
69
+ const slideAnim = isForward ? 'ds-nav-drill-forward' : 'ds-nav-drill-backward';
70
+ const timing = `${DRILL_ANIMATION_DURATION} ${DRILL_ANIMATION_EASING} both`;
71
+ return /*#__PURE__*/ jsx(NavPanel, {
72
+ resizable: resizable,
73
+ children: /*#__PURE__*/ jsx("div", {
74
+ className: "min-h-0 flex-1 overflow-hidden",
75
+ children: /*#__PURE__*/ jsxs("div", {
76
+ className: "flex motion-reduce:animate-none",
77
+ style: {
78
+ animation: `${slideAnim} ${timing}`
79
+ },
80
+ onAnimationEnd: clearTransition,
81
+ children: [
82
+ /*#__PURE__*/ jsx("div", {
83
+ className: "flex w-full shrink-0 flex-col gap-2 motion-reduce:animate-none",
84
+ style: {
85
+ animation: `${isForward ? 'ds-nav-blur-out' : 'ds-nav-blur-in'} ${timing}`
86
+ },
87
+ children: renderContent(isForward ? transition.fromLevel : drillLevel)
88
+ }),
89
+ /*#__PURE__*/ jsx("div", {
90
+ className: "flex w-full shrink-0 flex-col gap-2 motion-reduce:animate-none",
91
+ style: {
92
+ animation: `${isForward ? 'ds-nav-blur-in' : 'ds-nav-blur-out'} ${timing}`
93
+ },
94
+ children: renderContent(isForward ? drillLevel : transition.fromLevel)
95
+ })
96
+ ]
97
+ })
98
+ })
99
+ });
100
+ }
101
+ return /*#__PURE__*/ jsx(NavPanel, {
102
+ resizable: resizable,
103
+ children: renderContent(drillLevel)
104
+ });
105
+ };
106
+ ProductNavPanel.displayName = 'ProductNavPanel';
107
+ export { ProductNavPanel };
@@ -0,0 +1,11 @@
1
+ export { NavPanelSkeleton, type NavPanelSkeletonProps } from '../NavPanel';
2
+ export { type MatchNavResult, matchNav } from './matchNav';
3
+ export { findDrillNode, findFirstLinkPath } from './navUtils';
4
+ export { ProductNav, type ProductNavProps } from './ProductNav';
5
+ export { ProductNavBreadcrumbs } from './ProductNavBreadcrumbs';
6
+ export type { ProductNavContextValue } from './ProductNavContext';
7
+ export { useProductNavContext } from './ProductNavContext';
8
+ export { ProductNavPanel } from './ProductNavPanel';
9
+ export type { BreadcrumbSegment, NavConfig, NavConfigDrill, NavConfigGroup, NavConfigHeaderAction, NavConfigLink, NavConfigNode, NavConfigSectionHeader, NavStackEntry, } from './types';
10
+ export { pushPathname, useLocationPathname } from './useLocationPathname';
11
+ export { type UseProductNavResult, useProductNav } from './useProductNav';
@@ -0,0 +1,10 @@
1
+ import { NavPanelSkeleton } from "../NavPanel/index.js";
2
+ import { matchNav } from "./matchNav.js";
3
+ import { findDrillNode, findFirstLinkPath } from "./navUtils.js";
4
+ import { ProductNav } from "./ProductNav.js";
5
+ import { ProductNavBreadcrumbs } from "./ProductNavBreadcrumbs.js";
6
+ import { useProductNavContext } from "./ProductNavContext.js";
7
+ import { ProductNavPanel } from "./ProductNavPanel.js";
8
+ import { pushPathname, useLocationPathname } from "./useLocationPathname.js";
9
+ import { useProductNav } from "./useProductNav.js";
10
+ export { NavPanelSkeleton, ProductNav, ProductNavBreadcrumbs, ProductNavPanel, findDrillNode, findFirstLinkPath, matchNav, pushPathname, useLocationPathname, useProductNav, useProductNavContext };
@@ -28,7 +28,7 @@ const matchNav = (pathname, config)=>{
28
28
  breadcrumbSegments.push({
29
29
  type: 'link',
30
30
  label: config.productLabel,
31
- href: config.productPath
31
+ href: '/'
32
32
  });
33
33
  let segmentIndex = 0;
34
34
  let currentItems = config.items;
@@ -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;
@@ -8,7 +8,6 @@ export interface NavConfigHeaderAction {
8
8
  }
9
9
  export interface NavConfig {
10
10
  productLabel: string;
11
- productPath: string;
12
11
  items: NavConfigNode[];
13
12
  headerActions?: NavConfigHeaderAction[];
14
13
  }
@@ -36,6 +35,7 @@ export interface NavConfigDrill {
36
35
  label: string;
37
36
  description?: string;
38
37
  }[];
38
+ /** Render a visual divider after this item */
39
39
  dividerAfter?: boolean;
40
40
  }
41
41
  export interface NavConfigGroup {
@@ -45,6 +45,7 @@ export interface NavConfigGroup {
45
45
  children: NavConfigNode[];
46
46
  icon?: ComponentType<SvgIconProps>;
47
47
  defaultExpanded?: boolean;
48
+ /** Render a visual divider after this item */
48
49
  dividerAfter?: boolean;
49
50
  }
50
51
  export interface NavConfigSectionHeader {
@@ -0,0 +1,16 @@
1
+ import { type Dispatch, type SetStateAction } from 'react';
2
+ import type { BreadcrumbSegment, NavStackEntry } from './types';
3
+ export interface UseProductNavResult {
4
+ navStack: NavStackEntry[];
5
+ peekDepth: number;
6
+ setPeekDepth: Dispatch<SetStateAction<number>>;
7
+ breadcrumbSegments: BreadcrumbSegment[];
8
+ activeItemId: string | null;
9
+ }
10
+ /**
11
+ * Hook providing computed nav state + peekDepth management.
12
+ *
13
+ * Reads computed state from ProductNav context.
14
+ * `peekDepth` is the only local mutable state and resets on pathname changes.
15
+ */
16
+ export declare function useProductNav(): UseProductNavResult;
@@ -0,0 +1,19 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useProductNavContext } from "./ProductNavContext.js";
3
+ function useProductNav() {
4
+ const { pathname, navStack, breadcrumbSegments, activeItemId } = useProductNavContext();
5
+ const [peekDepth, setPeekDepth] = useState(0);
6
+ useEffect(()=>{
7
+ setPeekDepth(0);
8
+ }, [
9
+ pathname
10
+ ]);
11
+ return {
12
+ navStack,
13
+ peekDepth,
14
+ setPeekDepth,
15
+ breadcrumbSegments,
16
+ activeItemId
17
+ };
18
+ }
19
+ export { useProductNav };
@@ -1,14 +1,7 @@
1
1
  import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
2
2
  import { type TestableProps } from '../../utils/testId';
3
- import type { NavConfig } from './model';
4
3
  export interface RemoteShellProps extends HTMLAttributes<HTMLDivElement>, TestableProps {
5
4
  ref?: Ref<HTMLDivElement>;
6
5
  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;
13
6
  }
14
7
  export declare const RemoteShell: FC<RemoteShellProps>;