@wallarm-org/design-system 0.47.0 → 0.48.0-rc-feature-AS-1033.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 (30) hide show
  1. package/dist/components/AppShell/AppShellRemote.js +1 -1
  2. package/dist/components/AppShell/story-content/_storyConfigRenderer.d.ts +5 -3
  3. package/dist/components/AppShell/story-content/_storyConfigRenderer.js +44 -3
  4. package/dist/components/AppShell/story-content/_storyLib.d.ts +9 -0
  5. package/dist/components/AppShell/story-content/_storyLib.js +39 -0
  6. package/dist/components/AppShell/story-content/_storyRecentDropdown.d.ts +1 -0
  7. package/dist/components/AppShell/story-content/_storyRecentDropdown.js +89 -0
  8. package/dist/components/AppShell/story-content/index.d.ts +3 -1
  9. package/dist/components/AppShell/story-content/index.js +4 -2
  10. package/dist/components/Kbd/Kbd.d.ts +1 -1
  11. package/dist/components/Kbd/Kbd.js +1 -0
  12. package/dist/components/NavPanel/NavPanelSkeleton.d.ts +6 -0
  13. package/dist/components/NavPanel/NavPanelSkeleton.js +23 -0
  14. package/dist/components/NavPanel/index.d.ts +1 -0
  15. package/dist/components/NavPanel/index.js +2 -1
  16. package/dist/components/NavRail/NavRailSkeleton.d.ts +6 -0
  17. package/dist/components/NavRail/NavRailSkeleton.js +23 -0
  18. package/dist/components/NavRail/index.d.ts +1 -0
  19. package/dist/components/NavRail/index.js +2 -1
  20. package/dist/components/OverflowList/OverflowList.js +24 -12
  21. package/dist/components/ProductNav/index.d.ts +1 -0
  22. package/dist/components/ProductNav/index.js +2 -1
  23. package/dist/components/Table/mocks.js +40 -10
  24. package/dist/hooks/useOverflowItems.helpers.d.ts +15 -0
  25. package/dist/hooks/useOverflowItems.helpers.js +19 -0
  26. package/dist/hooks/useOverflowItems.js +80 -64
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +3 -3
  29. package/dist/metadata/components.json +885 -5
  30. package/package.json +1 -1
@@ -8,7 +8,7 @@ const AppShellRemote = ({ ref, className, children, ...props })=>{
8
8
  ref: ref,
9
9
  "data-slot": "app-shell-remote",
10
10
  "data-testid": testId,
11
- className: cn('[grid-area:remote] overflow-auto overscroll-none rounded-tl-12 border border-border-primary-light bg-bg-page-bg', className),
11
+ className: cn('[grid-area:remote] relative overflow-auto overscroll-none rounded-tl-12 border border-border-primary-light bg-bg-page-bg', className),
12
12
  children: children
13
13
  });
14
14
  };
@@ -1,7 +1,9 @@
1
- import type { FC } from 'react';
2
- import type { NavConfig } from '../../ProductNav';
1
+ import { type NavConfig } from '../../ProductNav';
2
+ import { type Product } from './_storyLib';
3
3
  export interface ConfigRemoteProps {
4
4
  config: NavConfig;
5
5
  basePath?: string;
6
6
  }
7
- export declare const ConfigRemote: FC<ConfigRemoteProps>;
7
+ export declare const RemoteForProduct: ({ product }: {
8
+ product: Product;
9
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,10 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { ProductNav, ProductNavBreadcrumbs, ProductNavPanel, useProductNavContext } from "../../ProductNav/index.js";
2
+ import { useEffect, useState } from "react";
3
+ import { NavPanel, NavPanelHeader } from "../../NavPanel/index.js";
4
+ import { NavPanelSkeleton, ProductNav, ProductNavBreadcrumbs, ProductNavPanel, useProductNavContext } from "../../ProductNav/index.js";
3
5
  import { RemoteShell, RemoteShellBreadcrumb, RemoteShellContent, RemoteShellPanel } from "../../RemoteShell/index.js";
6
+ import { HomeContent } from "./_storyHomeContent.js";
7
+ import { PRODUCT_CONFIGS } from "./_storyLib.js";
4
8
  const PageContent = ()=>{
5
9
  const { config, breadcrumbSegments } = useProductNavContext();
6
10
  const lastSegment = breadcrumbSegments[breadcrumbSegments.length - 1];
@@ -24,7 +28,35 @@ const PageContent = ()=>{
24
28
  ]
25
29
  });
26
30
  };
27
- const ConfigRemote = ({ config, basePath })=>/*#__PURE__*/ jsx(ProductNav, {
31
+ const ConfigRemote = ({ config, basePath })=>{
32
+ const [loading, setLoading] = useState(true);
33
+ useEffect(()=>{
34
+ setLoading(true);
35
+ const timer = setTimeout(()=>{
36
+ setLoading(false);
37
+ }, 2000);
38
+ return ()=>clearTimeout(timer);
39
+ }, [
40
+ config.productLabel
41
+ ]);
42
+ if (loading) return /*#__PURE__*/ jsxs(RemoteShell, {
43
+ children: [
44
+ /*#__PURE__*/ jsx(RemoteShellPanel, {
45
+ children: /*#__PURE__*/ jsxs(NavPanel, {
46
+ children: [
47
+ /*#__PURE__*/ jsx(NavPanelHeader, {
48
+ children: config.productLabel
49
+ }),
50
+ /*#__PURE__*/ jsx(NavPanelSkeleton, {
51
+ count: 6
52
+ })
53
+ ]
54
+ })
55
+ }),
56
+ /*#__PURE__*/ jsx(RemoteShellContent, {})
57
+ ]
58
+ });
59
+ return /*#__PURE__*/ jsx(ProductNav, {
28
60
  config: config,
29
61
  basePath: basePath,
30
62
  children: /*#__PURE__*/ jsxs(RemoteShell, {
@@ -43,4 +75,13 @@ const ConfigRemote = ({ config, basePath })=>/*#__PURE__*/ jsx(ProductNav, {
43
75
  ]
44
76
  })
45
77
  });
46
- export { ConfigRemote };
78
+ };
79
+ const RemoteForProduct = ({ product })=>{
80
+ if ('home' === product) return /*#__PURE__*/ jsx(HomeContent, {});
81
+ const { config } = PRODUCT_CONFIGS[product];
82
+ return /*#__PURE__*/ jsx(ConfigRemote, {
83
+ config: config,
84
+ basePath: `/${product}`
85
+ });
86
+ };
87
+ export { RemoteForProduct };
@@ -0,0 +1,9 @@
1
+ import { edgeNavConfig } from './_storyNavConfigs';
2
+ declare const KNOWN_PRODUCTS: readonly ["home", "edge", "ai-hypervisor", "infra-discovery", "security-testing", "settings"];
3
+ export type Product = (typeof KNOWN_PRODUCTS)[number];
4
+ export declare const PRODUCT_CONFIGS: Record<Exclude<Product, 'home'>, {
5
+ config: typeof edgeNavConfig;
6
+ }>;
7
+ export declare function deriveProduct(pathname: string): Product;
8
+ export declare function navigateToProduct(product: Product): void;
9
+ export {};
@@ -0,0 +1,39 @@
1
+ import { findFirstLinkPath, pushPathname } from "../../ProductNav/index.js";
2
+ import { aiHypervisorNavConfig, edgeNavConfig, infraDiscoveryNavConfig, securityTestingNavConfig, settingsNavConfig } from "./_storyNavConfigs.js";
3
+ const KNOWN_PRODUCTS = [
4
+ 'home',
5
+ 'edge',
6
+ 'ai-hypervisor',
7
+ 'infra-discovery',
8
+ 'security-testing',
9
+ 'settings'
10
+ ];
11
+ const PRODUCT_CONFIGS = {
12
+ edge: {
13
+ config: edgeNavConfig
14
+ },
15
+ 'ai-hypervisor': {
16
+ config: aiHypervisorNavConfig
17
+ },
18
+ 'infra-discovery': {
19
+ config: infraDiscoveryNavConfig
20
+ },
21
+ 'security-testing': {
22
+ config: securityTestingNavConfig
23
+ },
24
+ settings: {
25
+ config: settingsNavConfig
26
+ }
27
+ };
28
+ function deriveProduct(pathname) {
29
+ const segment = pathname.split('/').filter(Boolean)[0];
30
+ if (segment && KNOWN_PRODUCTS.includes(segment)) return segment;
31
+ return 'home';
32
+ }
33
+ function navigateToProduct(product) {
34
+ if ('home' === product) return void pushPathname('/home');
35
+ const { config } = PRODUCT_CONFIGS[product];
36
+ const firstPath = findFirstLinkPath(config.items) ?? '';
37
+ pushPathname(`/${product}/${firstPath}`);
38
+ }
39
+ export { PRODUCT_CONFIGS, deriveProduct, navigateToProduct };
@@ -0,0 +1 @@
1
+ export declare const RecentDropdown: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,89 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { History } from "../../../icons/index.js";
3
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemText, DropdownMenuLabel, DropdownMenuTrigger } from "../../DropdownMenu/index.js";
4
+ import { NavRailItem } from "../../NavRail/index.js";
5
+ import { Text } from "../../Text/index.js";
6
+ const RECENT_ITEMS = [
7
+ {
8
+ pageName: 'WAF Rules',
9
+ productName: 'Edge'
10
+ },
11
+ {
12
+ pageName: 'API Sessions',
13
+ dataPlane: 'US Cloud',
14
+ productName: 'Edge'
15
+ },
16
+ {
17
+ pageName: 'Prompt Inspector',
18
+ productName: 'AI Hypervisor'
19
+ },
20
+ {
21
+ pageName: 'Scanner Results',
22
+ dataPlane: 'EU Cloud',
23
+ productName: 'Security Testing'
24
+ },
25
+ {
26
+ pageName: 'Asset Inventory',
27
+ productName: 'Infra Discovery'
28
+ },
29
+ {
30
+ pageName: 'Pupu',
31
+ productName: 'Edge'
32
+ },
33
+ {
34
+ pageName: 'Pupupu',
35
+ dataPlane: 'US Cloud',
36
+ productName: 'Edge'
37
+ },
38
+ {
39
+ pageName: 'PuPuPuuu',
40
+ productName: 'AI Hypervisor'
41
+ },
42
+ {
43
+ pageName: 'MeowMeow',
44
+ dataPlane: 'EU Cloud',
45
+ productName: 'Security Testing'
46
+ },
47
+ {
48
+ pageName: '...',
49
+ productName: '....'
50
+ }
51
+ ];
52
+ const RecentDropdown = ()=>/*#__PURE__*/ jsxs(DropdownMenu, {
53
+ positioning: {
54
+ placement: 'right-start',
55
+ gutter: 8
56
+ },
57
+ children: [
58
+ /*#__PURE__*/ jsx(DropdownMenuTrigger, {
59
+ children: /*#__PURE__*/ jsx(NavRailItem, {
60
+ icon: History,
61
+ label: "Recent"
62
+ })
63
+ }),
64
+ /*#__PURE__*/ jsxs(DropdownMenuContent, {
65
+ className: "w-304 h-290 overscroll-none",
66
+ children: [
67
+ /*#__PURE__*/ jsx(DropdownMenuLabel, {
68
+ className: "sticky top-0 z-10 bg-bg-surface-2",
69
+ children: "Recent"
70
+ }),
71
+ RECENT_ITEMS.map((item)=>/*#__PURE__*/ jsx(DropdownMenuItem, {
72
+ children: /*#__PURE__*/ jsxs(DropdownMenuItemContent, {
73
+ children: [
74
+ /*#__PURE__*/ jsx(DropdownMenuItemText, {
75
+ children: item.pageName
76
+ }),
77
+ /*#__PURE__*/ jsx(Text, {
78
+ size: "xs",
79
+ color: "secondary",
80
+ children: item.dataPlane ? `${item.dataPlane} \u00b7 ${item.productName}` : item.productName
81
+ })
82
+ ]
83
+ })
84
+ }, `${item.pageName}-${item.productName}`))
85
+ ]
86
+ })
87
+ ]
88
+ });
89
+ export { RecentDropdown };
@@ -1,5 +1,7 @@
1
1
  export { AccountDropdown, type SidebarMode } from './_storyAccountDropdown';
2
- export { ConfigRemote } from './_storyConfigRenderer';
2
+ export { RemoteForProduct } from './_storyConfigRenderer';
3
3
  export { HomeContent } from './_storyHomeContent';
4
+ export { deriveProduct, navigateToProduct } from './_storyLib';
4
5
  export { aiHypervisorNavConfig, edgeNavConfig, infraDiscoveryNavConfig, securityTestingNavConfig, settingsNavConfig, } from './_storyNavConfigs';
5
6
  export { QuickHelpDropdown } from './_storyQuickHelpDropdown';
7
+ export { RecentDropdown } from './_storyRecentDropdown';
@@ -1,6 +1,8 @@
1
1
  import { AccountDropdown } from "./_storyAccountDropdown.js";
2
- import { ConfigRemote } from "./_storyConfigRenderer.js";
2
+ import { RemoteForProduct } from "./_storyConfigRenderer.js";
3
3
  import { HomeContent } from "./_storyHomeContent.js";
4
+ import { deriveProduct, navigateToProduct } from "./_storyLib.js";
4
5
  import { aiHypervisorNavConfig, edgeNavConfig, infraDiscoveryNavConfig, securityTestingNavConfig, settingsNavConfig } from "./_storyNavConfigs.js";
5
6
  import { QuickHelpDropdown } from "./_storyQuickHelpDropdown.js";
6
- export { AccountDropdown, ConfigRemote, HomeContent, QuickHelpDropdown, aiHypervisorNavConfig, edgeNavConfig, infraDiscoveryNavConfig, securityTestingNavConfig, settingsNavConfig };
7
+ import { RecentDropdown } from "./_storyRecentDropdown.js";
8
+ export { AccountDropdown, HomeContent, QuickHelpDropdown, RecentDropdown, RemoteForProduct, aiHypervisorNavConfig, deriveProduct, edgeNavConfig, infraDiscoveryNavConfig, navigateToProduct, securityTestingNavConfig, settingsNavConfig };
@@ -2,7 +2,7 @@ import type { ComponentProps, FC } from 'react';
2
2
  import { type VariantProps } from 'class-variance-authority';
3
3
  import type { TestableProps } from '../../utils/testId';
4
4
  declare const kbdVariants: (props?: ({
5
- size?: "small" | "medium" | null | undefined;
5
+ size?: "small" | "medium" | "xsmall" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  type KbdVariantsProps = VariantProps<typeof kbdVariants>;
8
8
  type KbdProps = ComponentProps<'kbd'> & KbdVariantsProps & TestableProps;
@@ -4,6 +4,7 @@ import { cn } from "../../utils/cn.js";
4
4
  const kbdVariants = cva(cn('inline-flex items-center justify-center gap-1 w-fit', 'border border-component-border-hotkey rounded-4 bg-bg-surface-2', 'font-sans font-medium', 'text-text-primary text-xs', 'pointer-events-none select-none'), {
5
5
  variants: {
6
6
  size: {
7
+ xsmall: 'h-16 min-w-20 p-2',
7
8
  small: 'h-20 min-w-20 p-4',
8
9
  medium: 'h-24 min-w-24 p-6'
9
10
  }
@@ -0,0 +1,6 @@
1
+ import type { FC, HTMLAttributes, Ref } from 'react';
2
+ export interface NavPanelSkeletonProps extends HTMLAttributes<HTMLDivElement> {
3
+ ref?: Ref<HTMLDivElement>;
4
+ count?: number;
5
+ }
6
+ export declare const NavPanelSkeleton: FC<NavPanelSkeletonProps>;
@@ -0,0 +1,23 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../utils/cn.js";
3
+ import { useTestId } from "../../utils/testId.js";
4
+ import { Skeleton } from "../Skeleton/index.js";
5
+ const NavPanelSkeleton = ({ ref, className, count = 6, ...props })=>{
6
+ const testId = useTestId('skeleton');
7
+ return /*#__PURE__*/ jsx("div", {
8
+ ...props,
9
+ ref: ref,
10
+ "data-slot": "nav-panel-skeleton",
11
+ "data-testid": testId,
12
+ className: cn('flex flex-col gap-6', className),
13
+ children: Array.from({
14
+ length: count
15
+ }, (_, i)=>/*#__PURE__*/ jsx(Skeleton, {
16
+ width: "100%",
17
+ height: "28px",
18
+ rounded: 6
19
+ }, i))
20
+ });
21
+ };
22
+ NavPanelSkeleton.displayName = 'NavPanelSkeleton';
23
+ export { NavPanelSkeleton };
@@ -8,3 +8,4 @@ export { NavPanelGroupLabel, type NavPanelGroupLabelProps } from './NavPanelGrou
8
8
  export { NavPanelHeader, type NavPanelHeaderProps } from './NavPanelHeader';
9
9
  export { NavPanelItem, type NavPanelItemProps } from './NavPanelItem';
10
10
  export { NavPanelSectionHeader, type NavPanelSectionHeaderProps } from './NavPanelSectionHeader';
11
+ export { NavPanelSkeleton, type NavPanelSkeletonProps } from './NavPanelSkeleton';
@@ -8,4 +8,5 @@ import { NavPanelGroupLabel } from "./NavPanelGroupLabel.js";
8
8
  import { NavPanelHeader } from "./NavPanelHeader.js";
9
9
  import { NavPanelItem } from "./NavPanelItem.js";
10
10
  import { NavPanelSectionHeader } from "./NavPanelSectionHeader.js";
11
- export { NavPanel, NavPanelBack, NavPanelDivider, NavPanelGroup, NavPanelGroupContent, NavPanelGroupItem, NavPanelGroupLabel, NavPanelHeader, NavPanelItem, NavPanelSectionHeader };
11
+ import { NavPanelSkeleton } from "./NavPanelSkeleton.js";
12
+ export { NavPanel, NavPanelBack, NavPanelDivider, NavPanelGroup, NavPanelGroupContent, NavPanelGroupItem, NavPanelGroupLabel, NavPanelHeader, NavPanelItem, NavPanelSectionHeader, NavPanelSkeleton };
@@ -0,0 +1,6 @@
1
+ import type { FC, HTMLAttributes, Ref } from 'react';
2
+ export interface NavRailSkeletonProps extends HTMLAttributes<HTMLDivElement> {
3
+ ref?: Ref<HTMLDivElement>;
4
+ count?: number;
5
+ }
6
+ export declare const NavRailSkeleton: FC<NavRailSkeletonProps>;
@@ -0,0 +1,23 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../utils/cn.js";
3
+ import { useTestId } from "../../utils/testId.js";
4
+ import { Skeleton } from "../Skeleton/index.js";
5
+ const NavRailSkeleton = ({ ref, className, count = 4, ...props })=>{
6
+ const testId = useTestId('skeleton');
7
+ return /*#__PURE__*/ jsx("div", {
8
+ ...props,
9
+ ref: ref,
10
+ "data-slot": "nav-rail-skeleton",
11
+ "data-testid": testId,
12
+ className: cn('flex flex-col gap-6', className),
13
+ children: Array.from({
14
+ length: count
15
+ }, (_, i)=>/*#__PURE__*/ jsx(Skeleton, {
16
+ width: "100%",
17
+ height: "28px",
18
+ rounded: 6
19
+ }, i))
20
+ });
21
+ };
22
+ NavRailSkeleton.displayName = 'NavRailSkeleton';
23
+ export { NavRailSkeleton };
@@ -4,3 +4,4 @@ export { useNavRailContext } from './NavRailContext';
4
4
  export { NavRailFooter, type NavRailFooterProps } from './NavRailFooter';
5
5
  export { NavRailItem, type NavRailItemProps } from './NavRailItem';
6
6
  export { NavRailSeparator, type NavRailSeparatorProps } from './NavRailSeparator';
7
+ export { NavRailSkeleton, type NavRailSkeletonProps } from './NavRailSkeleton';
@@ -4,4 +4,5 @@ import { useNavRailContext } from "./NavRailContext.js";
4
4
  import { NavRailFooter } from "./NavRailFooter.js";
5
5
  import { NavRailItem } from "./NavRailItem.js";
6
6
  import { NavRailSeparator } from "./NavRailSeparator.js";
7
- export { NavRail, NavRailBody, NavRailFooter, NavRailItem, NavRailSeparator, useNavRailContext };
7
+ import { NavRailSkeleton } from "./NavRailSkeleton.js";
8
+ export { NavRail, NavRailBody, NavRailFooter, NavRailItem, NavRailSeparator, NavRailSkeleton, useNavRailContext };
@@ -1,20 +1,23 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { memo, useCallback, useMemo } from "react";
2
+ import { memo, useCallback, useEffect, useMemo, useRef } from "react";
3
3
  import { useOverflowItems } from "../../hooks/index.js";
4
4
  import { cn } from "../../utils/cn.js";
5
5
  const OverflowListComponent = ({ items, itemRenderer, overflowRenderer, className, collapseFrom = 'end', minVisibleItems = 0, alwaysRenderOverflow = false, onOverflow, ...props })=>{
6
- const memoizedItemRenderer = useCallback((item)=>{
7
- const index = items.indexOf(item);
8
- return itemRenderer(item, index);
6
+ const indexMap = useMemo(()=>{
7
+ const map = new Map();
8
+ items.forEach((item, index)=>{
9
+ if (!map.has(item)) map.set(item, index);
10
+ });
11
+ return map;
9
12
  }, [
10
- items,
13
+ items
14
+ ]);
15
+ const memoizedItemRenderer = useCallback((item)=>itemRenderer(item, indexMap.get(item) ?? 0), [
16
+ indexMap,
11
17
  itemRenderer
12
18
  ]);
13
- const memoizedMeasurementRenderer = useCallback((item)=>{
14
- const index = items.indexOf(item);
15
- return itemRenderer(item, index);
16
- }, [
17
- items,
19
+ const memoizedMeasurementRenderer = useCallback((item)=>itemRenderer(item, indexMap.get(item) ?? 0), [
20
+ indexMap,
18
21
  itemRenderer
19
22
  ]);
20
23
  const { containerRef, visibleItems, hiddenItems, MeasurementContainer } = useOverflowItems({
@@ -41,8 +44,16 @@ const OverflowListComponent = ({ items, itemRenderer, overflowRenderer, classNam
41
44
  hiddenItems
42
45
  ]);
43
46
  const finalHiddenCount = finalHiddenItems.length;
44
- useMemo(()=>{
45
- if (onOverflow && finalHiddenItems.length > 0) onOverflow(finalHiddenItems);
47
+ const prevHiddenRef = useRef(null);
48
+ useEffect(()=>{
49
+ if (!onOverflow || 0 === finalHiddenItems.length) {
50
+ prevHiddenRef.current = finalHiddenItems;
51
+ return;
52
+ }
53
+ const prev = prevHiddenRef.current;
54
+ const changed = !prev || prev.length !== finalHiddenItems.length || finalHiddenItems.some((item, index)=>item !== prev[index]);
55
+ if (changed) onOverflow(finalHiddenItems);
56
+ prevHiddenRef.current = finalHiddenItems;
46
57
  }, [
47
58
  finalHiddenItems,
48
59
  onOverflow
@@ -65,6 +76,7 @@ const OverflowListComponent = ({ items, itemRenderer, overflowRenderer, classNam
65
76
  /*#__PURE__*/ jsx(MeasurementContainer, {}),
66
77
  /*#__PURE__*/ jsxs("div", {
67
78
  ref: containerRef,
79
+ "data-slot": "overflow-list",
68
80
  className: cn('flex w-full min-w-0', className),
69
81
  ...props,
70
82
  children: [
@@ -1,3 +1,4 @@
1
+ export { NavPanelSkeleton, type NavPanelSkeletonProps } from '../NavPanel';
1
2
  export { type MatchNavResult, matchNav } from './matchNav';
2
3
  export { findDrillNode, findFirstLinkPath } from './navUtils';
3
4
  export { ProductNav, type ProductNavProps } from './ProductNav';
@@ -1,3 +1,4 @@
1
+ import { NavPanelSkeleton } from "../NavPanel/index.js";
1
2
  import { matchNav } from "./matchNav.js";
2
3
  import { findDrillNode, findFirstLinkPath } from "./navUtils.js";
3
4
  import { ProductNav } from "./ProductNav.js";
@@ -6,4 +7,4 @@ import { useProductNavContext } from "./ProductNavContext.js";
6
7
  import { ProductNavPanel } from "./ProductNavPanel.js";
7
8
  import { pushPathname, useLocationPathname } from "./useLocationPathname.js";
8
9
  import { useProductNav } from "./useProductNav.js";
9
- export { ProductNav, ProductNavBreadcrumbs, ProductNavPanel, findDrillNode, findFirstLinkPath, matchNav, pushPathname, useLocationPathname, useProductNav, useProductNavContext };
10
+ export { NavPanelSkeleton, ProductNav, ProductNavBreadcrumbs, ProductNavPanel, findDrillNode, findFirstLinkPath, matchNav, pushPathname, useLocationPathname, useProductNav, useProductNavContext };
@@ -20,7 +20,10 @@ const securityEvents = [
20
20
  objectName: 'Rate limiting abuse on the payment endpoint',
21
21
  tags: [
22
22
  'api-abuse',
23
- 'account-takeover'
23
+ 'account-takeover',
24
+ 'credential-stuffing',
25
+ 'scanner',
26
+ 'brute-force'
24
27
  ],
25
28
  isActive: false,
26
29
  requests: 22000,
@@ -40,7 +43,10 @@ const securityEvents = [
40
43
  objectName: 'Mass assignment vulnerability in user profile',
41
44
  tags: [
42
45
  'api-abuse',
43
- 'account-takeover'
46
+ 'account-takeover',
47
+ 'credential-stuffing',
48
+ 'scanner',
49
+ 'brute-force'
44
50
  ],
45
51
  isActive: false,
46
52
  requests: 25000,
@@ -60,7 +66,10 @@ const securityEvents = [
60
66
  objectName: 'Insecure direct object reference in user data',
61
67
  tags: [
62
68
  'api-abuse',
63
- 'account-takeover'
69
+ 'account-takeover',
70
+ 'credential-stuffing',
71
+ 'scanner',
72
+ 'brute-force'
64
73
  ],
65
74
  isActive: true,
66
75
  requests: 30000,
@@ -80,7 +89,10 @@ const securityEvents = [
80
89
  objectName: 'Improper error handling leading to info leak',
81
90
  tags: [
82
91
  'api-abuse',
83
- 'account-takeover'
92
+ 'account-takeover',
93
+ 'credential-stuffing',
94
+ 'scanner',
95
+ 'brute-force'
84
96
  ],
85
97
  isActive: true,
86
98
  requests: 35000,
@@ -100,7 +112,10 @@ const securityEvents = [
100
112
  objectName: 'Broken authentication in the login API',
101
113
  tags: [
102
114
  'api-abuse',
103
- 'account-takeover'
115
+ 'account-takeover',
116
+ 'credential-stuffing',
117
+ 'scanner',
118
+ 'brute-force'
104
119
  ],
105
120
  isActive: true,
106
121
  requests: 20000,
@@ -120,7 +135,10 @@ const securityEvents = [
120
135
  objectName: 'Lack of resource validation in file upload',
121
136
  tags: [
122
137
  'api-abuse',
123
- 'account-takeover'
138
+ 'account-takeover',
139
+ 'credential-stuffing',
140
+ 'scanner',
141
+ 'brute-force'
124
142
  ],
125
143
  isActive: false,
126
144
  requests: 40000,
@@ -140,7 +158,10 @@ const securityEvents = [
140
158
  objectName: 'Server-side request forgery in image proxy',
141
159
  tags: [
142
160
  'api-abuse',
143
- 'account-takeover'
161
+ 'account-takeover',
162
+ 'credential-stuffing',
163
+ 'scanner',
164
+ 'brute-force'
144
165
  ],
145
166
  isActive: false,
146
167
  requests: 50000,
@@ -160,7 +181,10 @@ const securityEvents = [
160
181
  objectName: 'Unvalidated redirects and forwards in auth flow',
161
182
  tags: [
162
183
  'api-abuse',
163
- 'account-takeover'
184
+ 'account-takeover',
185
+ 'credential-stuffing',
186
+ 'scanner',
187
+ 'brute-force'
164
188
  ],
165
189
  isActive: true,
166
190
  requests: 75000,
@@ -180,7 +204,10 @@ const securityEvents = [
180
204
  objectName: 'SQL injection in the user ID',
181
205
  tags: [
182
206
  'api-abuse',
183
- 'account-takeover'
207
+ 'account-takeover',
208
+ 'credential-stuffing',
209
+ 'scanner',
210
+ 'brute-force'
184
211
  ],
185
212
  isActive: false,
186
213
  requests: 15000,
@@ -200,7 +227,10 @@ const securityEvents = [
200
227
  objectName: "Cross-site scripting in the API endpoint",
201
228
  tags: [
202
229
  'api-abuse',
203
- 'account-takeover'
230
+ 'account-takeover',
231
+ 'credential-stuffing',
232
+ 'scanner',
233
+ 'brute-force'
204
234
  ],
205
235
  isActive: false,
206
236
  requests: 18000,
@@ -0,0 +1,15 @@
1
+ export interface CalculateVisibleCountParams {
2
+ /** Width of each item in source order (px). */
3
+ itemWidths: number[];
4
+ /** Gap between flex children of the container (px). */
5
+ gap: number;
6
+ /** Available width of the container (px). */
7
+ availableWidth: number;
8
+ /** Measured width of the '+N' indicator (px); fallback — reserveSpace. */
9
+ indicatorWidth: number;
10
+ }
11
+ /**
12
+ * Pure arithmetic: how many leading items fit before an overflow indicator
13
+ * is required. Does not touch the DOM — safe to call on every resize frame.
14
+ */
15
+ export declare function calculateVisibleCount({ itemWidths, gap, availableWidth, indicatorWidth, }: CalculateVisibleCountParams): number;
@@ -0,0 +1,19 @@
1
+ function calculateVisibleCount({ itemWidths, gap, availableWidth, indicatorWidth }) {
2
+ if (0 === itemWidths.length) return 0;
3
+ if (availableWidth <= 0) return itemWidths.length;
4
+ let total = 0;
5
+ for(let i = 0; i < itemWidths.length; i++)total += (itemWidths[i] ?? 0) + (i > 0 ? gap : 0);
6
+ if (total <= availableWidth) return itemWidths.length;
7
+ const maxWidth = availableWidth - indicatorWidth - gap;
8
+ let accumulated = 0;
9
+ let count = 0;
10
+ for(let i = 0; i < itemWidths.length; i++){
11
+ const widthWithGap = (itemWidths[i] ?? 0) + (i > 0 ? gap : 0);
12
+ if (accumulated + widthWithGap <= maxWidth || 0 === i) {
13
+ accumulated += widthWithGap;
14
+ count++;
15
+ } else break;
16
+ }
17
+ return Math.max(count, 1);
18
+ }
19
+ export { calculateVisibleCount };