@wallarm-org/design-system 0.51.0-rc-feature-AS-1026.1 → 0.51.1-rc-fix-table-virtualization-scroll-loop.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 (97) 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/AppShell/story-content/_storyNavConfigs.js +5 -0
  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/ParameterPath/ParameterPath.js +63 -65
  10. package/dist/components/ParameterPath/ParameterPathRow.d.ts +14 -0
  11. package/dist/components/ParameterPath/ParameterPathRow.js +67 -0
  12. package/dist/components/ParameterPath/classes.d.ts +3 -0
  13. package/dist/components/ParameterPath/classes.js +12 -1
  14. package/dist/components/ParameterPath/constants.d.ts +11 -0
  15. package/dist/components/ParameterPath/constants.js +15 -0
  16. package/dist/components/ParameterPath/types.d.ts +26 -0
  17. package/dist/components/ParameterPath/useParameterPathTruncation.js +8 -10
  18. package/dist/components/{ProductNav → RemoteShell}/HeaderActions.d.ts +1 -1
  19. package/dist/components/{ProductNav → RemoteShell}/NavItemsList.d.ts +1 -1
  20. package/dist/components/RemoteShell/NavPanelContent.d.ts +6 -0
  21. package/dist/components/RemoteShell/NavPanelContent.js +65 -0
  22. package/dist/components/RemoteShell/RemoteShell.d.ts +7 -0
  23. package/dist/components/RemoteShell/RemoteShell.js +109 -9
  24. package/dist/components/RemoteShell/RemoteShellBreadcrumb.js +39 -4
  25. package/dist/components/RemoteShell/RemoteShellContent.d.ts +1 -0
  26. package/dist/components/RemoteShell/RemoteShellContent.js +7 -3
  27. package/dist/components/RemoteShell/RemoteShellPanel.d.ts +4 -2
  28. package/dist/components/RemoteShell/RemoteShellPanel.js +76 -3
  29. package/dist/components/RemoteShell/index.d.ts +2 -0
  30. package/dist/components/RemoteShell/index.js +2 -1
  31. package/dist/components/{ProductNav/ProductNavContext.d.ts → RemoteShell/model/RemoteShellContext.d.ts} +3 -3
  32. package/dist/components/RemoteShell/model/RemoteShellContext.js +9 -0
  33. package/dist/components/RemoteShell/model/index.d.ts +5 -0
  34. package/dist/components/RemoteShell/model/index.js +5 -0
  35. package/dist/components/{ProductNav → RemoteShell/model}/matchNav.js +1 -1
  36. package/dist/components/{ProductNav → RemoteShell/model}/types.d.ts +2 -3
  37. package/dist/components/Table/TableBody/TableBodyVirtualizedContainer.js +3 -5
  38. package/dist/components/Table/TableBody/TableBodyVirtualizedWindow.js +3 -5
  39. package/dist/components/Table/TableBody/useResetVirtualizerOnDataChange.d.ts +3 -3
  40. package/dist/components/Table/TableBody/useResetVirtualizerOnDataChange.js +6 -8
  41. package/dist/components/Table/TableContext/TableProvider.js +1 -7
  42. package/dist/components/Table/TableContext/types.d.ts +0 -3
  43. package/dist/components/Table/TableInner/TableInnerContainer.js +4 -9
  44. package/dist/components/Table/TableInner/TableInnerWindow.js +4 -9
  45. package/dist/components/Table/hooks/index.d.ts +1 -1
  46. package/dist/components/Table/hooks/index.js +2 -2
  47. package/dist/components/Table/hooks/useEndReached.d.ts +19 -0
  48. package/dist/components/Table/hooks/{infiniteScroll/useScrollEdge.js → useEndReached.js} +11 -15
  49. package/dist/components/Table/lib/constants.d.ts +0 -3
  50. package/dist/components/Table/lib/constants.js +1 -3
  51. package/dist/components/Table/lib/index.d.ts +1 -3
  52. package/dist/components/Table/lib/index.js +2 -4
  53. package/dist/components/Table/mocks.d.ts +0 -13
  54. package/dist/components/Table/mocks.js +1 -59
  55. package/dist/components/Table/types.d.ts +1 -11
  56. package/dist/index.d.ts +1 -2
  57. package/dist/index.js +2 -3
  58. package/dist/metadata/components.json +67 -313
  59. package/dist/utils/hasTextSelection.d.ts +1 -0
  60. package/dist/utils/hasTextSelection.js +2 -0
  61. package/dist/utils/range.d.ts +1 -0
  62. package/dist/utils/range.js +4 -0
  63. package/package.json +1 -1
  64. package/dist/components/ProductNav/ProductNav.d.ts +0 -13
  65. package/dist/components/ProductNav/ProductNav.js +0 -109
  66. package/dist/components/ProductNav/ProductNavBreadcrumbs.d.ts +0 -2
  67. package/dist/components/ProductNav/ProductNavBreadcrumbs.js +0 -38
  68. package/dist/components/ProductNav/ProductNavContext.js +0 -9
  69. package/dist/components/ProductNav/ProductNavPanel.d.ts +0 -6
  70. package/dist/components/ProductNav/ProductNavPanel.js +0 -107
  71. package/dist/components/ProductNav/index.d.ts +0 -11
  72. package/dist/components/ProductNav/index.js +0 -10
  73. package/dist/components/ProductNav/useProductNav.d.ts +0 -16
  74. package/dist/components/ProductNav/useProductNav.js +0 -19
  75. package/dist/components/Table/hooks/infiniteScroll/index.d.ts +0 -1
  76. package/dist/components/Table/hooks/infiniteScroll/index.js +0 -2
  77. package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.d.ts +0 -18
  78. package/dist/components/Table/hooks/infiniteScroll/useInfiniteScroll.js +0 -34
  79. package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.d.ts +0 -16
  80. package/dist/components/Table/hooks/infiniteScroll/useInitialAnchor.js +0 -28
  81. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.d.ts +0 -15
  82. package/dist/components/Table/hooks/infiniteScroll/usePrependScrollAnchor.js +0 -28
  83. package/dist/components/Table/hooks/infiniteScroll/useScrollEdge.d.ts +0 -20
  84. package/dist/components/Table/lib/detectDataChange.d.ts +0 -4
  85. package/dist/components/Table/lib/detectDataChange.js +0 -7
  86. package/dist/components/Table/lib/getRowKey.d.ts +0 -4
  87. package/dist/components/Table/lib/getRowKey.js +0 -2
  88. /package/dist/components/{ProductNav → RemoteShell}/HeaderActions.js +0 -0
  89. /package/dist/components/{ProductNav → RemoteShell}/NavItemsList.js +0 -0
  90. /package/dist/components/{ProductNav → RemoteShell/model}/matchNav.d.ts +0 -0
  91. /package/dist/components/{ProductNav → RemoteShell/model}/navUtils.d.ts +0 -0
  92. /package/dist/components/{ProductNav → RemoteShell/model}/navUtils.js +0 -0
  93. /package/dist/components/{ProductNav → RemoteShell/model}/types.js +0 -0
  94. /package/dist/components/{ProductNav → RemoteShell/model}/useDrillTransition.d.ts +0 -0
  95. /package/dist/components/{ProductNav → RemoteShell/model}/useDrillTransition.js +0 -0
  96. /package/dist/components/{ProductNav → RemoteShell/model}/useLocationPathname.d.ts +0 -0
  97. /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;
@@ -1,6 +1,7 @@
1
1
  import { CircleDashed, Filter, Plus } from "../../../icons/index.js";
2
2
  const edgeNavConfig = {
3
3
  productLabel: 'Edge',
4
+ productPath: '/edge',
4
5
  headerActions: [
5
6
  {
6
7
  icon: Filter,
@@ -340,6 +341,7 @@ const edgeNavConfig = {
340
341
  };
341
342
  const aiHypervisorNavConfig = {
342
343
  productLabel: 'AI Hypervisor',
344
+ productPath: '/ai-hypervisor',
343
345
  items: [
344
346
  {
345
347
  type: 'link',
@@ -454,6 +456,7 @@ const aiHypervisorNavConfig = {
454
456
  };
455
457
  const infraDiscoveryNavConfig = {
456
458
  productLabel: 'Infra Discovery',
459
+ productPath: '/infra-discovery',
457
460
  headerActions: [
458
461
  {
459
462
  icon: Filter,
@@ -554,6 +557,7 @@ const infraDiscoveryNavConfig = {
554
557
  };
555
558
  const securityTestingNavConfig = {
556
559
  productLabel: 'Security Testing',
560
+ productPath: '/security-testing',
557
561
  items: [
558
562
  {
559
563
  type: 'link',
@@ -627,6 +631,7 @@ const securityTestingNavConfig = {
627
631
  };
628
632
  const settingsNavConfig = {
629
633
  productLabel: 'Settings',
634
+ productPath: '/settings',
630
635
  items: [
631
636
  {
632
637
  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', 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,17 +1,27 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useRef } from "react";
3
+ import { useControlled } from "../../hooks/index.js";
3
4
  import { cn } from "../../utils/cn.js";
5
+ import { hasTextSelection } from "../../utils/hasTextSelection.js";
4
6
  import { TestIdProvider } from "../../utils/testId.js";
5
7
  import { Tooltip, TooltipContent, TooltipTrigger } from "../Tooltip/index.js";
6
8
  import { buildFullPathLabel } from "./buildFullPathLabel.js";
9
+ import { EXPAND_KEYS } from "./constants.js";
7
10
  import { formatAsFilter } from "./formatAsFilter.js";
8
- import { ParameterPathEllipsis } from "./ParameterPathEllipsis.js";
9
- import { ParameterPathEncoding } from "./ParameterPathEncoding.js";
10
- import { ParameterPathJoint } from "./ParameterPathJoint.js";
11
- import { ParameterPathMethod } from "./ParameterPathMethod.js";
12
- import { ParameterPathSegment } from "./ParameterPathSegment.js";
11
+ import { ParameterPathRow } from "./ParameterPathRow.js";
13
12
  import { useParameterPathTruncation } from "./useParameterPathTruncation.js";
14
- const ParameterPath = ({ ref, method, segments, encoding, attack = false, copyFormat = formatAsFilter, className, 'data-testid': testId, ...rest })=>{
13
+ const ParameterPath = ({ ref, method, segments, encoding, attack = false, expandable = false, expanded, defaultExpanded = false, onExpandedChange, copyFormat = formatAsFilter, className, 'data-testid': testId, ...rest })=>{
14
+ const [expandedState, setExpandedUncontrolled] = useControlled({
15
+ controlled: expanded,
16
+ default: defaultExpanded
17
+ });
18
+ const setExpanded = useCallback((next)=>{
19
+ setExpandedUncontrolled(next);
20
+ onExpandedChange?.(next);
21
+ }, [
22
+ setExpandedUncontrolled,
23
+ onExpandedChange
24
+ ]);
15
25
  const handleCopy = useCallback((event)=>{
16
26
  const text = copyFormat({
17
27
  method,
@@ -36,63 +46,28 @@ const ParameterPath = ({ ref, method, segments, encoding, attack = false, copyFo
36
46
  hasMethod: Boolean(method),
37
47
  hasEncoding: Boolean(encoding)
38
48
  });
39
- const lastIndex = segments.length - 1;
40
- const indices = isTruncated && segments.length > 2 ? visibleSegmentIndices : null;
41
- const renderRow = (forMeasurement)=>{
42
- const visibleIdx = forMeasurement || null === indices ? Array.from({
43
- length: segments.length
44
- }, (_, i)=>i) : indices;
45
- const items = [];
46
- const measure = (slot)=>forMeasurement ? slot : void 0;
47
- if (method) items.push(/*#__PURE__*/ jsx(ParameterPathMethod, {
48
- method: method,
49
- "data-measure": measure('method')
50
- }, "method"));
51
- visibleIdx.forEach((segIndex, position)=>{
52
- const value = segments[segIndex];
53
- if (void 0 === value) return;
54
- const isLast = segIndex === lastIndex;
55
- const isFirstShown = 0 === position;
56
- const showJointBefore = !(isFirstShown && !method);
57
- if (showJointBefore) items.push(/*#__PURE__*/ jsx(ParameterPathJoint, {
58
- "data-measure": measure('joint')
59
- }, `j-${segIndex}-pre`));
60
- const isCollapsedBoundary = !forMeasurement && null !== indices && 0 === position && 2 === visibleIdx.length;
61
- items.push(/*#__PURE__*/ jsx(ParameterPathSegment, {
62
- index: segIndex,
63
- variant: isLast ? 'highlighted' : 'default',
64
- withZap: isLast && attack,
65
- "data-measure": measure('segment'),
66
- children: value
67
- }, `s-${segIndex}`));
68
- if (isCollapsedBoundary) items.push(/*#__PURE__*/ jsx(ParameterPathJoint, {}, "ellipsis-joint-pre"), /*#__PURE__*/ jsx(ParameterPathEllipsis, {}, "ellipsis"));
69
- });
70
- if (encoding) items.push(/*#__PURE__*/ jsx(ParameterPathJoint, {
71
- "data-measure": measure('joint')
72
- }, "enc-joint"), /*#__PURE__*/ jsx(ParameterPathEncoding, {
73
- "data-measure": measure('encoding'),
74
- children: encoding
75
- }, "enc"));
76
- return items;
77
- };
78
- const visibleRow = /*#__PURE__*/ jsx("div", {
79
- ref: containerRef,
80
- "data-row": "visible",
81
- className: "flex items-center gap-0 min-w-0 overflow-hidden",
82
- children: renderRow(false)
83
- });
84
- const measurementRow = /*#__PURE__*/ jsx("div", {
85
- ref: measurementRef,
86
- "data-row": "measure",
87
- "aria-hidden": "true",
88
- className: "flex items-center gap-0 absolute left-[-9999px] top-0 invisible pointer-events-none",
89
- children: /*#__PURE__*/ jsx(TestIdProvider, {
90
- value: void 0,
91
- children: renderRow(true)
92
- })
93
- });
49
+ const collapsible = isTruncated && segments.length > 2;
50
+ const isExpanded = Boolean(expandedState) && collapsible;
51
+ const interactive = expandable && collapsible;
52
+ const indices = collapsible && !isExpanded ? visibleSegmentIndices : null;
53
+ const toggleExpanded = useCallback(()=>{
54
+ if (hasTextSelection()) return;
55
+ setExpanded(!isExpanded);
56
+ }, [
57
+ isExpanded,
58
+ setExpanded
59
+ ]);
60
+ const handleKeyDown = useCallback((event)=>{
61
+ if (EXPAND_KEYS.includes(event.key)) {
62
+ event.preventDefault();
63
+ setExpanded(!isExpanded);
64
+ }
65
+ }, [
66
+ isExpanded,
67
+ setExpanded
68
+ ]);
94
69
  return /*#__PURE__*/ jsxs(Tooltip, {
95
- disabled: !isTruncated,
70
+ disabled: !isTruncated || isExpanded,
96
71
  children: [
97
72
  /*#__PURE__*/ jsx(TooltipTrigger, {
98
73
  asChild: true,
@@ -101,14 +76,37 @@ const ParameterPath = ({ ref, method, segments, encoding, attack = false, copyFo
101
76
  "data-testid": testId,
102
77
  "data-slot": "parameter-path",
103
78
  "data-truncated": isTruncated || void 0,
79
+ "data-expanded": isExpanded || void 0,
104
80
  ref: ref,
105
81
  onCopy: handleCopy,
106
- className: cn('relative flex items-center min-w-0', className),
82
+ role: interactive ? 'button' : void 0,
83
+ tabIndex: interactive ? 0 : void 0,
84
+ "aria-expanded": interactive ? isExpanded : void 0,
85
+ onClick: interactive ? toggleExpanded : void 0,
86
+ onKeyDown: interactive ? handleKeyDown : void 0,
87
+ className: cn('relative flex items-center min-w-0', interactive && 'cursor-pointer', className),
107
88
  children: /*#__PURE__*/ jsxs(TestIdProvider, {
108
89
  value: testId,
109
90
  children: [
110
- visibleRow,
111
- measurementRow
91
+ /*#__PURE__*/ jsx(ParameterPathRow, {
92
+ ref: containerRef,
93
+ forMeasurement: false,
94
+ isExpanded: isExpanded,
95
+ indices: indices,
96
+ method: method,
97
+ segments: segments,
98
+ encoding: encoding,
99
+ attack: attack
100
+ }),
101
+ /*#__PURE__*/ jsx(ParameterPathRow, {
102
+ ref: measurementRef,
103
+ forMeasurement: true,
104
+ indices: null,
105
+ method: method,
106
+ segments: segments,
107
+ encoding: encoding,
108
+ attack: attack
109
+ })
112
110
  ]
113
111
  })
114
112
  })
@@ -0,0 +1,14 @@
1
+ import type { FC, Ref } from 'react';
2
+ import type { HttpMethodName } from '../HttpMethod';
3
+ interface ParameterPathRowProps {
4
+ ref?: Ref<HTMLDivElement>;
5
+ method?: HttpMethodName;
6
+ segments: string[];
7
+ encoding?: string;
8
+ attack: boolean;
9
+ forMeasurement: boolean;
10
+ indices: number[] | null;
11
+ isExpanded?: boolean;
12
+ }
13
+ export declare const ParameterPathRow: FC<ParameterPathRowProps>;
14
+ export {};
@@ -0,0 +1,67 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { range } from "../../utils/range.js";
3
+ import { TestIdProvider } from "../../utils/testId.js";
4
+ import { rowVariants } from "./classes.js";
5
+ import { MEASURE, ROW } from "./constants.js";
6
+ import { ParameterPathEllipsis } from "./ParameterPathEllipsis.js";
7
+ import { ParameterPathEncoding } from "./ParameterPathEncoding.js";
8
+ import { ParameterPathJoint } from "./ParameterPathJoint.js";
9
+ import { ParameterPathMethod } from "./ParameterPathMethod.js";
10
+ import { ParameterPathSegment } from "./ParameterPathSegment.js";
11
+ const ParameterPathRow = ({ ref, method, segments, encoding, attack, forMeasurement, indices, isExpanded = false })=>{
12
+ const lastIndex = segments.length - 1;
13
+ const visibleIdx = forMeasurement || null === indices ? range(segments.length) : indices;
14
+ const measure = (slot)=>forMeasurement ? slot : void 0;
15
+ const items = [];
16
+ if (method) items.push(/*#__PURE__*/ jsx(ParameterPathMethod, {
17
+ method: method,
18
+ "data-measure": measure(MEASURE.method)
19
+ }, "method"));
20
+ visibleIdx.forEach((segIndex, position)=>{
21
+ const value = segments[segIndex];
22
+ if (void 0 === value) return;
23
+ const isLast = segIndex === lastIndex;
24
+ const isFirstShown = 0 === position;
25
+ const showJointBefore = !(isFirstShown && !method);
26
+ if (showJointBefore) items.push(/*#__PURE__*/ jsx(ParameterPathJoint, {
27
+ "data-measure": measure(MEASURE.joint)
28
+ }, `j-${segIndex}-pre`));
29
+ const isCollapsedBoundary = !forMeasurement && null !== indices && 0 === position && 2 === visibleIdx.length;
30
+ items.push(/*#__PURE__*/ jsx(ParameterPathSegment, {
31
+ index: segIndex,
32
+ variant: isLast ? 'highlighted' : 'default',
33
+ withZap: isLast && attack,
34
+ "data-measure": measure(MEASURE.segment),
35
+ children: value
36
+ }, `s-${segIndex}`));
37
+ if (isCollapsedBoundary) items.push(/*#__PURE__*/ jsx(ParameterPathJoint, {}, "ellipsis-joint-pre"), /*#__PURE__*/ jsx(ParameterPathEllipsis, {}, "ellipsis"));
38
+ });
39
+ if (encoding) items.push(/*#__PURE__*/ jsx(ParameterPathJoint, {
40
+ "data-measure": measure(MEASURE.joint)
41
+ }, "enc-joint"), /*#__PURE__*/ jsx(ParameterPathEncoding, {
42
+ "data-measure": measure(MEASURE.encoding),
43
+ children: encoding
44
+ }, "enc"));
45
+ if (forMeasurement) return /*#__PURE__*/ jsx("div", {
46
+ ref: ref,
47
+ "data-slot": "parameter-path-row",
48
+ "data-row": ROW.measure,
49
+ "aria-hidden": "true",
50
+ className: "flex items-center gap-0 absolute left-[-9999px] top-0 invisible pointer-events-none",
51
+ children: /*#__PURE__*/ jsx(TestIdProvider, {
52
+ value: void 0,
53
+ children: items
54
+ })
55
+ });
56
+ return /*#__PURE__*/ jsx("div", {
57
+ ref: ref,
58
+ "data-slot": "parameter-path-row",
59
+ "data-row": ROW.visible,
60
+ className: rowVariants({
61
+ expanded: isExpanded
62
+ }),
63
+ children: items
64
+ });
65
+ };
66
+ ParameterPathRow.displayName = 'ParameterPathRow';
67
+ export { ParameterPathRow };
@@ -1,3 +1,6 @@
1
+ export declare const rowVariants: (props?: ({
2
+ expanded?: boolean | null | undefined;
3
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
1
4
  export declare const segmentVariants: (props?: ({
2
5
  variant?: "default" | "highlighted" | null | undefined;
3
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -1,4 +1,15 @@
1
1
  import { cva } from "class-variance-authority";
2
+ const rowVariants = cva('flex items-center gap-0 min-w-0', {
3
+ variants: {
4
+ expanded: {
5
+ true: 'flex-wrap',
6
+ false: 'overflow-hidden'
7
+ }
8
+ },
9
+ defaultVariants: {
10
+ expanded: false
11
+ }
12
+ });
2
13
  const segmentVariants = cva('flex items-center justify-center gap-2 shrink-0 text-sm leading-5 whitespace-nowrap font-sans', {
3
14
  variants: {
4
15
  variant: {
@@ -22,4 +33,4 @@ const ellipsisVariants = cva([
22
33
  'h-20 px-2 gap-2',
23
34
  'text-text-secondary'
24
35
  ]);
25
- export { ellipsisVariants, encodingVariants, jointVariants, segmentVariants };
36
+ export { ellipsisVariants, encodingVariants, jointVariants, rowVariants, segmentVariants };
@@ -0,0 +1,11 @@
1
+ export declare const MEASURE: {
2
+ readonly method: "method";
3
+ readonly joint: "joint";
4
+ readonly segment: "segment";
5
+ readonly encoding: "encoding";
6
+ };
7
+ export declare const ROW: {
8
+ readonly visible: "visible";
9
+ readonly measure: "measure";
10
+ };
11
+ export declare const EXPAND_KEYS: readonly string[];
@@ -0,0 +1,15 @@
1
+ const MEASURE = {
2
+ method: 'method',
3
+ joint: 'joint',
4
+ segment: 'segment',
5
+ encoding: 'encoding'
6
+ };
7
+ const ROW = {
8
+ visible: 'visible',
9
+ measure: 'measure'
10
+ };
11
+ const EXPAND_KEYS = [
12
+ 'Enter',
13
+ ' '
14
+ ];
15
+ export { EXPAND_KEYS, MEASURE, ROW };
@@ -12,5 +12,31 @@ export interface ParameterPathProps extends Omit<HTMLAttributes<HTMLDivElement>,
12
12
  segments: string[];
13
13
  encoding?: string;
14
14
  attack?: boolean;
15
+ /**
16
+ * Opt in to click-to-expand. When `true`, a *truncated* path becomes
17
+ * interactive: clicking the `…` collapse indicator (or the path) expands it
18
+ * inline to show every segment, and clicking again collapses it back to
19
+ * `first … last`. No effect when the path already fits without truncation.
20
+ *
21
+ * `expandable` only controls the affordance (whether the user can toggle);
22
+ * the open/closed state is owned by `expanded` / `defaultExpanded`.
23
+ */
24
+ expandable?: boolean;
25
+ /**
26
+ * Controlled expanded state. When provided, the component does not manage its
27
+ * own state — pair it with {@link onExpandedChange}.
28
+ */
29
+ expanded?: boolean;
30
+ /**
31
+ * Initial expanded state for the uncontrolled case. Ignored when `expanded`
32
+ * is provided. Defaults to `false`.
33
+ */
34
+ defaultExpanded?: boolean;
35
+ /**
36
+ * Called with the next expanded state whenever the user toggles the path.
37
+ * Required for controlled usage; also useful for analytics in the
38
+ * uncontrolled case.
39
+ */
40
+ onExpandedChange?: (expanded: boolean) => void;
15
41
  copyFormat?: (data: CopyFormatData) => string;
16
42
  }
@@ -1,10 +1,10 @@
1
1
  import { useLayoutEffect, useState } from "react";
2
+ import { range } from "../../utils/range.js";
2
3
  import { useContainerWidth } from "../Table/lib/useContainerWidth.js";
4
+ import { MEASURE } from "./constants.js";
3
5
  const computeTruncation = ({ containerWidth, methodWidth, encodingWidth, segmentWidths, jointsWidth })=>{
4
6
  const segCount = segmentWidths.length;
5
- const allIndices = Array.from({
6
- length: segCount
7
- }, (_, i)=>i);
7
+ const allIndices = range(segCount);
8
8
  if (segCount <= 2 || containerWidth <= 0) return {
9
9
  isTruncated: false,
10
10
  visibleSegmentIndices: allIndices
@@ -27,17 +27,15 @@ const useParameterPathTruncation = ({ containerRef, measurementRef, segmentCount
27
27
  const containerWidth = useContainerWidth(containerRef);
28
28
  const [result, setResult] = useState({
29
29
  isTruncated: false,
30
- visibleSegmentIndices: Array.from({
31
- length: segmentCount
32
- }, (_, i)=>i)
30
+ visibleSegmentIndices: range(segmentCount)
33
31
  });
34
32
  useLayoutEffect(()=>{
35
33
  const root = measurementRef.current;
36
34
  if (!root) return;
37
- const methodEl = root.querySelector('[data-measure="method"]');
38
- const encodingEl = root.querySelector('[data-measure="encoding"]');
39
- const jointEls = Array.from(root.querySelectorAll('[data-measure="joint"]'));
40
- const segmentEls = Array.from(root.querySelectorAll('[data-measure="segment"]'));
35
+ const methodEl = root.querySelector(`[data-measure="${MEASURE.method}"]`);
36
+ const encodingEl = root.querySelector(`[data-measure="${MEASURE.encoding}"]`);
37
+ const jointEls = Array.from(root.querySelectorAll(`[data-measure="${MEASURE.joint}"]`));
38
+ const segmentEls = Array.from(root.querySelectorAll(`[data-measure="${MEASURE.segment}"]`));
41
39
  const segmentWidths = segmentEls.map((el)=>el.getBoundingClientRect().width);
42
40
  const methodWidth = hasMethod && methodEl ? methodEl.getBoundingClientRect().width : 0;
43
41
  const encodingWidth = hasEncoding && encodingEl ? encodingEl.getBoundingClientRect().width : 0;
@@ -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,65 @@
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: rawLevel })=>{
8
+ const { config, navStack, effectiveActiveItemId, navigate, drillInto, goBack } = useRemoteShellContext();
9
+ const level = Math.min(rawLevel, navStack.length - 1);
10
+ const entry = navStack[level];
11
+ const hasHeaderActions = !!config.headerActions?.length;
12
+ if (0 === level) return /*#__PURE__*/ jsxs(Fragment, {
13
+ children: [
14
+ hasHeaderActions ? /*#__PURE__*/ jsxs("div", {
15
+ className: "sticky top-0 z-10 flex shrink-0 items-center justify-between p-4 bg-bg-surface-2",
16
+ children: [
17
+ /*#__PURE__*/ jsx(Text, {
18
+ size: "sm",
19
+ weight: "medium",
20
+ children: config.productLabel
21
+ }),
22
+ /*#__PURE__*/ jsx(HeaderActions, {
23
+ actions: config.headerActions
24
+ })
25
+ ]
26
+ }) : /*#__PURE__*/ jsx(NavPanelHeader, {
27
+ children: config.productLabel
28
+ }),
29
+ /*#__PURE__*/ jsx(NavItemsList, {
30
+ items: config.items,
31
+ activeItemId: effectiveActiveItemId,
32
+ onNavigate: navigate,
33
+ onDrillClick: drillInto
34
+ })
35
+ ]
36
+ });
37
+ const parentEntry = navStack[level - 1];
38
+ const drillNode = findDrillNode(parentEntry.items, parentEntry.activeItemId);
39
+ const backLabel = drillNode?.label ?? 'Back';
40
+ return /*#__PURE__*/ jsxs(Fragment, {
41
+ children: [
42
+ /*#__PURE__*/ jsxs("div", {
43
+ className: "sticky top-0 z-10 flex flex-col gap-2 bg-bg-surface-1",
44
+ children: [
45
+ /*#__PURE__*/ jsx(NavPanelHeader, {
46
+ children: entry.title
47
+ }),
48
+ /*#__PURE__*/ jsx(NavPanelBack, {
49
+ onClick: goBack,
50
+ children: backLabel
51
+ }),
52
+ /*#__PURE__*/ jsx(NavPanelDivider, {})
53
+ ]
54
+ }),
55
+ /*#__PURE__*/ jsx(NavItemsList, {
56
+ items: entry.items,
57
+ activeItemId: effectiveActiveItemId,
58
+ onNavigate: navigate,
59
+ onDrillClick: drillInto
60
+ })
61
+ ]
62
+ });
63
+ };
64
+ NavPanelContent.displayName = 'NavPanelContent';
65
+ 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>;