@uipath/apollo-vertex 1.2.0 → 1.4.0

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 (54) hide show
  1. package/dist/lib/i18n.d.ts +10 -0
  2. package/dist/lib/table-features.d.ts +38 -0
  3. package/dist/lib/table-features.js +32 -0
  4. package/dist/locales/en.json +5 -0
  5. package/dist/registry/calendar/calendar.js +2 -2
  6. package/dist/registry/command/command.js +3 -0
  7. package/dist/registry/confidence-signal/confidence-signal-chip.js +1 -1
  8. package/dist/registry/data-table/data-table-column-header.d.ts +5 -4
  9. package/dist/registry/data-table/data-table-column-header.js +21 -18
  10. package/dist/registry/data-table/data-table-expand-toggle.d.ts +5 -4
  11. package/dist/registry/data-table/data-table-expand-toggle.js +1 -1
  12. package/dist/registry/data-table/data-table-filters.d.ts +4 -3
  13. package/dist/registry/data-table/data-table-filters.js +4 -4
  14. package/dist/registry/data-table/data-table-pagination.d.ts +5 -4
  15. package/dist/registry/data-table/data-table-pagination.js +2 -3
  16. package/dist/registry/data-table/data-table-search.d.ts +5 -4
  17. package/dist/registry/data-table/data-table-search.js +2 -2
  18. package/dist/registry/data-table/data-table-toolbar.d.ts +5 -4
  19. package/dist/registry/data-table/data-table-view-options.d.ts +5 -4
  20. package/dist/registry/data-table/data-table-view-options.js +2 -2
  21. package/dist/registry/data-table/data-table.d.ts +13 -12
  22. package/dist/registry/data-table/data-table.js +9 -12
  23. package/dist/registry/data-table/index.d.ts +3 -2
  24. package/dist/registry/data-table/index.js +1 -1
  25. package/dist/registry/filter-dropdown/filter-dropdown.d.ts +4 -4
  26. package/dist/registry/filter-dropdown/filter-dropdown.js +1 -1
  27. package/dist/registry/shell/shell-company.js +2 -1
  28. package/dist/registry/shell/shell-locale-provider.d.ts +2 -1
  29. package/dist/registry/shell/shell-locale-provider.js +12 -8
  30. package/dist/registry/shell/shell-minimal-nav-item.d.ts +4 -3
  31. package/dist/registry/shell/shell-minimal-nav-item.js +3 -7
  32. package/dist/registry/shell/shell-nav-active.d.ts +12 -0
  33. package/dist/registry/shell/shell-nav-active.js +24 -0
  34. package/dist/registry/shell/shell-nav-label.d.ts +7 -0
  35. package/dist/registry/shell/shell-nav-label.js +54 -0
  36. package/dist/registry/shell/shell-sidebar.js +126 -114
  37. package/dist/registry/shell/shell-text.d.ts +2 -2
  38. package/dist/registry/shell/shell-text.js +3 -2
  39. package/dist/registry/shell/shell-translation-key.d.ts +5 -0
  40. package/dist/registry/shell/shell.d.ts +6 -3
  41. package/dist/registry/shell/shell.js +18 -13
  42. package/dist/registry/solution-tests/config.d.ts +5 -5
  43. package/dist/registry/solution-tests/solution-tests-view.js +1 -1
  44. package/dist/registry/table-chart/table-chart-view.js +9 -5
  45. package/dist/registry/timeline/timeline-marker.js +2 -2
  46. package/dist/registry/use-data-table/types.d.ts +3 -2
  47. package/dist/registry/use-data-table/useColumnVisibility.d.ts +3 -3
  48. package/dist/registry/use-data-table/useDataTable.d.ts +8 -7
  49. package/dist/registry/use-data-table/useEntityColumns.d.ts +2 -2
  50. package/dist/registry/use-data-table/useEntityDataTable.d.ts +3 -3
  51. package/package.json +2 -2
  52. package/skills/setup/SKILL.md +123 -0
  53. package/dist/registry/use-data-table/useReactTableCompat.d.ts +0 -13
  54. package/dist/registry/use-data-table/useReactTableCompat.js +0 -9
@@ -1,5 +1,5 @@
1
- import type { Column } from "@tanstack/react-table";
2
1
  import { type ReactNode } from "react";
2
+ import type { DataTableColumn, RowData } from "../../lib/table-features";
3
3
  interface FilterDropdownOption {
4
4
  label: string;
5
5
  value: string;
@@ -7,14 +7,14 @@ interface FilterDropdownOption {
7
7
  className?: string;
8
8
  }>;
9
9
  }
10
- interface FilterDropdownProps<TData = unknown, TValue = unknown> {
10
+ interface FilterDropdownProps<TData extends RowData = RowData, TValue = unknown> {
11
11
  title: string;
12
12
  options: FilterDropdownOption[];
13
13
  className?: string;
14
14
  /** Multi-select (default) or single-select mode */
15
15
  multiSelect?: boolean;
16
16
  /** TanStack Table column integration (optional) */
17
- column?: Column<TData, TValue>;
17
+ column?: DataTableColumn<TData, TValue>;
18
18
  /** Standalone value — used when no column is provided */
19
19
  value?: string[] | string;
20
20
  /** Standalone onChange — used when no column is provided */
@@ -56,6 +56,6 @@ interface FilterDropdownProps<TData = unknown, TValue = unknown> {
56
56
  /** Known options for selected values that may not be loaded yet (used for the trigger label) */
57
57
  selectedOptions?: FilterDropdownOption[];
58
58
  }
59
- declare function FilterDropdown<TData, TValue>({ title, options, className, multiSelect, column, value: valueProp, onChange: onChangeProp, enableSearch, searchThreshold, searchPlaceholder, noOptionsMessage, noResultsMessage, align, popoverWidth, isLoading, hasMore, onLoadMore, loadingMessage, onSearchChange, searchDebounceMs, error, errorMessage, onRetry, retryLabel, selectedOptions, }: FilterDropdownProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
59
+ declare function FilterDropdown<TData extends RowData = RowData, TValue = unknown>({ title, options, className, multiSelect, column, value: valueProp, onChange: onChangeProp, enableSearch, searchThreshold, searchPlaceholder, noOptionsMessage, noResultsMessage, align, popoverWidth, isLoading, hasMore, onLoadMore, loadingMessage, onSearchChange, searchDebounceMs, error, errorMessage, onRetry, retryLabel, selectedOptions, }: FilterDropdownProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
60
60
  export { FilterDropdown };
61
61
  export type { FilterDropdownOption, FilterDropdownProps };
@@ -2,12 +2,12 @@
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { ChevronDownIcon, SearchIcon, XIcon } from "lucide-react";
4
4
  import { useState } from "react";
5
- import { useVertexTranslation } from "../../lib/vertex-translation.js";
6
5
  import { Button } from "../button/button.js";
7
6
  import { Input } from "../input/input.js";
8
7
  import { Popover, PopoverContent, PopoverTrigger } from "../popover/popover.js";
9
8
  import { Separator } from "../separator/separator.js";
10
9
  import { cn } from "../../lib/utils.js";
10
+ import { useVertexTranslation } from "../../lib/vertex-translation.js";
11
11
  import { FilterDropdownOptionRow } from "./filter-dropdown-option.js";
12
12
  import { FILTER_DROPDOWN_LIST_SLOT, FilterDropdownError, FilterDropdownLoadingMore, FilterDropdownSentinel, FilterDropdownSkeleton } from "./filter-dropdown-states.js";
13
13
  import { useFilterDropdownSearch } from "./use-filter-dropdown-search.js";
@@ -3,11 +3,11 @@ import { Link } from "@tanstack/react-router";
3
3
  import { AnimatePresence, motion } from "framer-motion";
4
4
  import { PanelLeft } from "lucide-react";
5
5
  import { useState } from "react";
6
- import { useVertexTranslation } from "../../lib/vertex-translation.js";
7
6
  import { Button } from "../button/button.js";
8
7
  import { useSidebar } from "../sidebar/sidebar.js";
9
8
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../tooltip/tooltip.js";
10
9
  import { cn } from "../../lib/utils.js";
10
+ import { useVertexTranslation } from "../../lib/vertex-translation.js";
11
11
  import { fastFadeTransition, iconHoverScale, scaleVariants, textFadeVariants } from "./shell-animations.js";
12
12
  import { CompanyLogoIcon } from "./shell-company-logo.js";
13
13
  function CollapsedLogo({ companyLogo, sidebarHovered, onExpand }) {
@@ -162,6 +162,7 @@ const Company = ({ companyName, productName, companyLogo, sidebarHovered = false
162
162
  children: /*#__PURE__*/ jsx(Button, {
163
163
  variant: "ghost",
164
164
  size: "icon-sm",
165
+ "aria-label": t("close_sidebar"),
165
166
  onClick: toggleSidebar,
166
167
  className: "ml-auto shrink-0 text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-foreground cursor-pointer",
167
168
  children: /*#__PURE__*/ jsx(PanelLeft, {
@@ -1,7 +1,8 @@
1
1
  import { type PropsWithChildren, type ReactNode } from "react";
2
2
  interface LocaleProviderProps {
3
3
  loadingElement?: ReactNode;
4
+ configureI18n?: () => Promise<void>;
4
5
  }
5
6
  export declare const LocaleProviderComponent: ({ children }: PropsWithChildren) => ReactNode;
6
- export declare const LocaleProvider: ({ children, loadingElement, }: PropsWithChildren<LocaleProviderProps>) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element;
7
+ export declare const LocaleProvider: ({ children, loadingElement, configureI18n, }: PropsWithChildren<LocaleProviderProps>) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element;
7
8
  export {};
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { useEffect, useEffectEvent, useState } from "react";
4
- import { useVertexTranslation } from "../../lib/vertex-translation.js";
5
4
  import { Spinner } from "../spinner/spinner.js";
6
5
  import { configurei18n } from "../../lib/i18n.js";
6
+ import { useVertexTranslation } from "../../lib/vertex-translation.js";
7
7
  import { LANGUAGE_CHANGED_EVENT } from "./shell-constants.js";
8
8
  const LocaleProviderComponent = ({ children })=>{
9
9
  const { i18n } = useVertexTranslation();
@@ -21,15 +21,19 @@ const LocaleProviderComponent = ({ children })=>{
21
21
  }, []);
22
22
  return children;
23
23
  };
24
- const LocaleProvider = ({ children, loadingElement })=>{
24
+ const LocaleProvider = ({ children, loadingElement, configureI18n = configurei18n })=>{
25
25
  const [isConfigured, setIsConfigured] = useState(false);
26
- const configure = async ()=>{
27
- await configurei18n();
28
- setIsConfigured(true);
29
- };
30
26
  useEffect(()=>{
31
- configure();
32
- }, []);
27
+ let cancelled = false;
28
+ configureI18n().then(()=>{
29
+ if (!cancelled) setIsConfigured(true);
30
+ });
31
+ return ()=>{
32
+ cancelled = true;
33
+ };
34
+ }, [
35
+ configureI18n
36
+ ]);
33
37
  if (!isConfigured) return loadingElement ?? /*#__PURE__*/ jsx("div", {
34
38
  className: "flex h-full w-full items-center justify-center",
35
39
  children: /*#__PURE__*/ jsx(Spinner, {
@@ -1,7 +1,8 @@
1
- import type { TranslationKey } from "./shell-translation-key";
1
+ import type { ShellNavLabel } from "./shell-translation-key";
2
2
  interface MinimalNavItemProps {
3
3
  to: string;
4
- label: TranslationKey;
4
+ active: boolean;
5
+ label: ShellNavLabel;
5
6
  }
6
- export declare const MinimalNavItem: ({ to, label }: MinimalNavItemProps) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const MinimalNavItem: ({ to, active, label }: MinimalNavItemProps) => import("react/jsx-runtime").JSX.Element;
7
8
  export {};
@@ -1,16 +1,12 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { Link, useLocation } from "@tanstack/react-router";
2
+ import { Link } from "@tanstack/react-router";
3
3
  import { cn } from "../../lib/utils.js";
4
4
  import { Text } from "./shell-text.js";
5
- const MinimalNavItem = ({ to, label })=>{
6
- const { pathname } = useLocation();
7
- const isActive = pathname === to;
8
- return /*#__PURE__*/ jsx(Link, {
5
+ const MinimalNavItem = ({ to, active, label })=>/*#__PURE__*/ jsx(Link, {
9
6
  to: to,
10
- className: cn("px-4 py-1.5 rounded-full text-sm font-medium transition-colors duration-200 shrink-0 whitespace-nowrap", isActive ? "bg-[oklch(0.92_0.035_218)] dark:bg-primary-900/30 text-primary-700 dark:text-primary-400 font-semibold" : "text-muted-foreground hover:text-foreground hover:bg-black/[0.04] dark:hover:bg-white/[0.06]"),
7
+ className: cn("px-4 py-1.5 rounded-full text-sm font-medium transition-colors duration-200 shrink-0 whitespace-nowrap", active ? "bg-[oklch(0.92_0.035_218)] dark:bg-primary-900/30 text-primary-700 dark:text-primary-400 font-semibold" : "text-muted-foreground hover:text-foreground hover:bg-black/[0.04] dark:hover:bg-white/[0.06]"),
11
8
  children: /*#__PURE__*/ jsx(Text, {
12
9
  value: label
13
10
  })
14
11
  });
15
- };
16
12
  export { MinimalNavItem };
@@ -0,0 +1,12 @@
1
+ export declare function navPathIsActive(pathname: string, path: string): boolean;
2
+ export declare function navItemIsCurrent(pathname: string, path: string, childPaths?: readonly string[]): boolean;
3
+ export declare function mostSpecificActivePath(pathname: string, paths: readonly string[]): string | null;
4
+ export declare function navItemState(pathname: string, item: {
5
+ path: string;
6
+ to?: string;
7
+ childPaths?: readonly string[];
8
+ }): {
9
+ href: string;
10
+ prefixActive: boolean;
11
+ current: boolean;
12
+ };
@@ -0,0 +1,24 @@
1
+ function navPathIsActive(pathname, path) {
2
+ if ("/" === path) return "/" === pathname;
3
+ return pathname === path || pathname.startsWith(`${path}/`);
4
+ }
5
+ function navItemIsCurrent(pathname, path, childPaths = []) {
6
+ return navPathIsActive(pathname, path) && !childPaths.some((childPath)=>navPathIsActive(pathname, childPath));
7
+ }
8
+ function mostSpecificActivePath(pathname, paths) {
9
+ let match = null;
10
+ for (const path of paths)if (navPathIsActive(pathname, path)) {
11
+ if (null === match || path.length > match.length) match = path;
12
+ }
13
+ return match;
14
+ }
15
+ function navItemState(pathname, item) {
16
+ const childPaths = item.childPaths ?? [];
17
+ const childActive = childPaths.some((childPath)=>navPathIsActive(pathname, childPath));
18
+ return {
19
+ href: item.to ?? item.path,
20
+ prefixActive: navPathIsActive(pathname, item.path) || childActive,
21
+ current: navItemIsCurrent(pathname, item.path, childPaths)
22
+ };
23
+ }
24
+ export { mostSpecificActivePath, navItemIsCurrent, navItemState, navPathIsActive };
@@ -0,0 +1,7 @@
1
+ export interface NavCatalog {
2
+ namespaces: readonly string[];
3
+ exists: (key: string, namespace: string) => boolean;
4
+ translate: (key: string, namespace: string) => string;
5
+ }
6
+ export declare function navCatalogFromHook(i18n: object): NavCatalog;
7
+ export declare function readNavLabel(catalog: NavCatalog, key: string): string;
@@ -0,0 +1,54 @@
1
+ import { VERTEX_NAMESPACE } from "../../lib/vertex-translation.js";
2
+ function configuredNamespaces(defaultNS) {
3
+ if ("string" == typeof defaultNS) return defaultNS.length > 0 ? [
4
+ defaultNS
5
+ ] : [
6
+ "translation"
7
+ ];
8
+ if (!Array.isArray(defaultNS)) return [
9
+ "translation"
10
+ ];
11
+ const namespaces = [];
12
+ for (const namespace of defaultNS)if ("string" == typeof namespace && namespace.length > 0) namespaces.push(namespace);
13
+ return namespaces.length > 0 ? namespaces : [
14
+ "translation"
15
+ ];
16
+ }
17
+ function lookupNamespaces(defaultNS) {
18
+ const configured = configuredNamespaces(defaultNS);
19
+ if (configured.includes(VERTEX_NAMESPACE)) return configured;
20
+ return [
21
+ ...configured,
22
+ VERTEX_NAMESPACE
23
+ ];
24
+ }
25
+ function isNamespacedI18n(value) {
26
+ return "options" in value && "exists" in value && "function" == typeof value.exists && "t" in value && "function" == typeof value.t;
27
+ }
28
+ function navCatalogFromHook(i18n) {
29
+ if (!isNamespacedI18n(i18n)) return {
30
+ namespaces: [
31
+ "translation",
32
+ VERTEX_NAMESPACE
33
+ ],
34
+ exists: ()=>false,
35
+ translate: (key)=>key
36
+ };
37
+ return {
38
+ namespaces: lookupNamespaces(i18n.options.defaultNS),
39
+ exists: (key, namespace)=>i18n.exists(key, {
40
+ ns: namespace
41
+ }),
42
+ translate: (key, namespace)=>{
43
+ const value = i18n.t(key, {
44
+ ns: namespace
45
+ });
46
+ return "string" == typeof value ? value : key;
47
+ }
48
+ };
49
+ }
50
+ function readNavLabel(catalog, key) {
51
+ for (const namespace of catalog.namespaces)if (catalog.exists(key, namespace)) return catalog.translate(key, namespace);
52
+ return key;
53
+ }
54
+ export { navCatalogFromHook, readNavLabel };
@@ -4,45 +4,54 @@ import { Link, useLocation } from "@tanstack/react-router";
4
4
  import { AnimatePresence, motion } from "framer-motion";
5
5
  import { ChevronDown } from "lucide-react";
6
6
  import { useEffect, useState } from "react";
7
- import { useVertexTranslation } from "../../lib/vertex-translation.js";
8
7
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../collapsible/collapsible.js";
9
8
  import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, useSidebar } from "../sidebar/sidebar.js";
10
9
  import { cn } from "../../lib/utils.js";
10
+ import { useVertexTranslation } from "../../lib/vertex-translation.js";
11
11
  import { fastFadeTransition, iconHoverScale, textFadeVariants } from "./shell-animations.js";
12
12
  import { Company } from "./shell-company.js";
13
13
  import { MinimalCompany } from "./shell-minimal-company.js";
14
14
  import { MinimalNavItem } from "./shell-minimal-nav-item.js";
15
+ import { mostSpecificActivePath, navItemState } from "./shell-nav-active.js";
16
+ import { navCatalogFromHook, readNavLabel } from "./shell-nav-label.js";
15
17
  import { Text } from "./shell-text.js";
16
18
  import { UserProfile } from "./shell-user-profile.js";
17
19
  const activeNavClass = "text-sidebar-foreground/85 hover:text-sidebar-foreground data-[active=true]:text-primary-700 dark:data-[active=true]:text-primary-400 data-[active=true]:font-semibold data-[active=true]:bg-primary-100/40 dark:data-[active=true]:bg-primary-900/30";
18
20
  const navButtonClass = `font-medium ${activeNavClass}`;
19
21
  const subButtonClass = activeNavClass;
22
+ const prefixActiveClass = "font-semibold text-primary-700 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-400 active:text-primary-700 dark:active:text-primary-400";
23
+ const currentPillClass = "bg-primary-100/40 dark:bg-primary-900/30";
20
24
  const ShellSidebar = ({ companyName, productName, variant, companyLogo, navItems })=>{
21
- if ("minimal" === variant) return /*#__PURE__*/ jsxs("header", {
22
- className: "relative flex items-center justify-between px-4 sm:px-6 lg:px-8 py-6 transition-[padding] duration-300 ease-in-out",
23
- children: [
24
- /*#__PURE__*/ jsx(MinimalCompany, {
25
- companyName: companyName,
26
- productName: productName,
27
- companyLogo: companyLogo
28
- }),
29
- navItems.length > 0 && /*#__PURE__*/ jsx("nav", {
30
- className: "absolute left-1/2 -translate-x-1/2 flex items-center bg-muted dark:bg-[oklch(0.24_0.033_254)] rounded-full p-1.5 overflow-x-auto scrollbar-thin",
31
- children: navItems.map((item)=>/*#__PURE__*/ jsx(MinimalNavItem, {
32
- to: item.path,
33
- label: item.label
34
- }, item.path))
35
- }),
36
- /*#__PURE__*/ jsx("div", {
37
- className: "flex items-center gap-2",
38
- children: /*#__PURE__*/ jsx(UserProfile, {
39
- isCollapsed: true,
40
- collapsedMenuSide: "bottom",
41
- collapsedMenuAlign: "end"
25
+ const { pathname } = useLocation();
26
+ if ("minimal" === variant) {
27
+ const activePath = mostSpecificActivePath(pathname, navItems.map((item)=>item.path));
28
+ return /*#__PURE__*/ jsxs("header", {
29
+ className: "relative flex items-center justify-between px-4 sm:px-6 lg:px-8 py-6 transition-[padding] duration-300 ease-in-out",
30
+ children: [
31
+ /*#__PURE__*/ jsx(MinimalCompany, {
32
+ companyName: companyName,
33
+ productName: productName,
34
+ companyLogo: companyLogo
35
+ }),
36
+ navItems.length > 0 && /*#__PURE__*/ jsx("nav", {
37
+ className: "absolute left-1/2 -translate-x-1/2 flex items-center bg-muted dark:bg-[oklch(0.24_0.033_254)] rounded-full p-1.5 overflow-x-auto scrollbar-thin",
38
+ children: navItems.map((item)=>/*#__PURE__*/ jsx(MinimalNavItem, {
39
+ to: item.to ?? item.path,
40
+ active: item.path === activePath,
41
+ label: item.label
42
+ }, item.path))
43
+ }),
44
+ /*#__PURE__*/ jsx("div", {
45
+ className: "flex items-center gap-2",
46
+ children: /*#__PURE__*/ jsx(UserProfile, {
47
+ isCollapsed: true,
48
+ collapsedMenuSide: "bottom",
49
+ collapsedMenuAlign: "end"
50
+ })
42
51
  })
43
- })
44
- ]
45
- });
52
+ ]
53
+ });
54
+ }
46
55
  return /*#__PURE__*/ jsx(SidebarNav, {
47
56
  companyName: companyName,
48
57
  productName: productName,
@@ -51,8 +60,9 @@ const ShellSidebar = ({ companyName, productName, variant, companyLogo, navItems
51
60
  });
52
61
  };
53
62
  function SidebarNav({ companyName, productName, companyLogo, navItems }) {
54
- const { t } = useVertexTranslation();
55
- const { state, toggleSidebar } = useSidebar();
63
+ const { t, i18n } = useVertexTranslation();
64
+ const catalog = navCatalogFromHook(i18n);
65
+ const { state } = useSidebar();
56
66
  const { pathname } = useLocation();
57
67
  const isCollapsed = "collapsed" === state;
58
68
  const [sidebarHovered, setSidebarHovered] = useState(false);
@@ -75,24 +85,16 @@ function SidebarNav({ companyName, productName, companyLogo, navItems }) {
75
85
  pathname,
76
86
  navItems
77
87
  ]);
78
- const handleMenuClick = (path)=>{
79
- if (isCollapsed) {
80
- toggleSidebar();
81
- setExpandedItems((prev)=>new Set(prev).add(path));
82
- } else setExpandedItems((prev)=>{
88
+ const toggleGroup = (path)=>{
89
+ setExpandedItems((prev)=>{
83
90
  const next = new Set(prev);
84
91
  if (next.has(path)) next.delete(path);
85
92
  else next.add(path);
86
93
  return next;
87
94
  });
88
95
  };
89
- const isActive = (path)=>{
90
- if ("/" === path) return "/" === pathname;
91
- return pathname === path || pathname.startsWith(`${path}/`);
92
- };
93
- const isParentActive = (item)=>item.subItems?.some((sub)=>isActive(sub.path)) ?? false;
94
96
  const getTooltipText = (label)=>{
95
- if ("string" == typeof label) return t(label);
97
+ if ("string" == typeof label) return readNavLabel(catalog, label);
96
98
  return t(label.i18nKey, label.values);
97
99
  };
98
100
  return /*#__PURE__*/ jsxs(Sidebar, {
@@ -119,97 +121,107 @@ function SidebarNav({ companyName, productName, companyLogo, navItems }) {
119
121
  children: /*#__PURE__*/ jsx(SidebarMenu, {
120
122
  children: navItems.map((item)=>{
121
123
  const Icon = item.icon;
122
- const active = isActive(item.path);
123
- const parentActive = isParentActive(item);
124
124
  const isExpanded = expandedItems.has(item.path);
125
- if (item.subItems && item.subItems.length > 0) {
126
- const showParentActive = isCollapsed && parentActive;
127
- return /*#__PURE__*/ jsx(Collapsible, {
128
- open: isExpanded && !isCollapsed,
129
- onOpenChange: ()=>handleMenuClick(item.path),
130
- className: "group/collapsible",
131
- children: /*#__PURE__*/ jsxs(SidebarMenuItem, {
132
- children: [
133
- /*#__PURE__*/ jsx(CollapsibleTrigger, {
134
- asChild: true,
135
- children: /*#__PURE__*/ jsxs(SidebarMenuButton, {
125
+ const childPaths = item.subItems?.map((sub)=>sub.path) ?? [];
126
+ const row = navItemState(pathname, {
127
+ path: item.path,
128
+ to: item.to,
129
+ childPaths
130
+ });
131
+ if (item.subItems && item.subItems.length > 0) return /*#__PURE__*/ jsx(Collapsible, {
132
+ open: isExpanded && !isCollapsed,
133
+ onOpenChange: ()=>toggleGroup(item.path),
134
+ className: "group/collapsible",
135
+ children: /*#__PURE__*/ jsxs(SidebarMenuItem, {
136
+ children: [
137
+ /*#__PURE__*/ jsxs("div", {
138
+ className: cn("flex w-full min-w-0 items-center rounded-md", !isCollapsed && row.current && currentPillClass, !isCollapsed && !row.current && "hover:bg-sidebar-accent/50"),
139
+ children: [
140
+ /*#__PURE__*/ jsx(SidebarMenuButton, {
141
+ asChild: true,
136
142
  tooltip: getTooltipText(item.label),
137
- isActive: showParentActive,
138
- className: navButtonClass,
139
- children: [
140
- /*#__PURE__*/ jsx(motion.span, {
141
- className: "inline-flex items-center justify-center shrink-0",
142
- ...isCollapsed ? {
143
- whileHover: iconHoverScale
144
- } : {},
145
- children: /*#__PURE__*/ jsx(Icon, {
146
- className: "size-4 shrink-0"
147
- })
148
- }),
149
- /*#__PURE__*/ jsx(AnimatePresence, {
150
- initial: false,
151
- children: !isCollapsed && /*#__PURE__*/ jsx(motion.span, {
152
- variants: textFadeVariants,
153
- initial: "initial",
154
- animate: "animate",
155
- exit: "exit",
156
- transition: fastFadeTransition,
157
- className: "whitespace-nowrap truncate",
158
- children: /*#__PURE__*/ jsx(Text, {
159
- value: item.label
143
+ isActive: isCollapsed && row.current,
144
+ className: cn(navButtonClass, row.prefixActive && prefixActiveClass, !isCollapsed && "w-auto min-w-0 flex-1 bg-transparent hover:bg-transparent"),
145
+ children: /*#__PURE__*/ jsxs(Link, {
146
+ to: row.href,
147
+ children: [
148
+ /*#__PURE__*/ jsx(motion.span, {
149
+ className: "inline-flex items-center justify-center shrink-0",
150
+ ...isCollapsed ? {
151
+ whileHover: iconHoverScale
152
+ } : {},
153
+ children: /*#__PURE__*/ jsx(Icon, {
154
+ className: "size-4 shrink-0"
160
155
  })
161
- }, "text")
156
+ }),
157
+ /*#__PURE__*/ jsx(AnimatePresence, {
158
+ initial: false,
159
+ children: !isCollapsed && /*#__PURE__*/ jsx(motion.span, {
160
+ variants: textFadeVariants,
161
+ initial: "initial",
162
+ animate: "animate",
163
+ exit: "exit",
164
+ transition: fastFadeTransition,
165
+ className: "whitespace-nowrap truncate",
166
+ children: /*#__PURE__*/ jsx(Text, {
167
+ value: item.label
168
+ })
169
+ }, "text")
170
+ })
171
+ ]
172
+ })
173
+ }),
174
+ !isCollapsed && /*#__PURE__*/ jsx(CollapsibleTrigger, {
175
+ asChild: true,
176
+ children: /*#__PURE__*/ jsx("button", {
177
+ type: "button",
178
+ "aria-expanded": isExpanded,
179
+ "aria-label": t(isExpanded ? "nav_collapse" : "nav_expand", {
180
+ label: getTooltipText(item.label)
162
181
  }),
163
- /*#__PURE__*/ jsx(AnimatePresence, {
164
- initial: false,
165
- children: !isCollapsed && /*#__PURE__*/ jsx(motion.div, {
166
- variants: textFadeVariants,
167
- initial: "initial",
168
- animate: "animate",
169
- exit: "exit",
170
- transition: fastFadeTransition,
171
- className: "ml-auto",
172
- children: /*#__PURE__*/ jsx(ChevronDown, {
173
- className: cn("size-4 transition-transform duration-200", isExpanded && "rotate-180")
174
- })
175
- }, "chevron")
182
+ className: "flex size-8 shrink-0 items-center justify-center text-sidebar-foreground/70 hover:text-sidebar-foreground",
183
+ children: /*#__PURE__*/ jsx(ChevronDown, {
184
+ className: cn("size-4 transition-transform duration-200", isExpanded && "rotate-180")
176
185
  })
177
- ]
186
+ })
178
187
  })
179
- }),
180
- /*#__PURE__*/ jsx(CollapsibleContent, {
181
- children: /*#__PURE__*/ jsx(SidebarMenuSub, {
182
- className: "ml-4 mr-0 mt-1 gap-0.5 pl-3 pr-0",
183
- children: item.subItems.map((subItem)=>{
184
- const subActive = isActive(subItem.path);
185
- return /*#__PURE__*/ jsx(SidebarMenuSubItem, {
186
- children: /*#__PURE__*/ jsx(SidebarMenuSubButton, {
187
- asChild: true,
188
- isActive: subActive,
189
- className: cn("cursor-pointer whitespace-nowrap", subButtonClass),
190
- children: /*#__PURE__*/ jsx(Link, {
191
- to: subItem.path,
192
- children: /*#__PURE__*/ jsx(Text, {
193
- value: subItem.label
194
- })
188
+ ]
189
+ }),
190
+ /*#__PURE__*/ jsx(CollapsibleContent, {
191
+ children: /*#__PURE__*/ jsx(SidebarMenuSub, {
192
+ className: "ml-4 mr-0 mt-1 gap-0.5 pl-3 pr-0",
193
+ children: item.subItems.map((subItem)=>{
194
+ const sub = navItemState(pathname, {
195
+ path: subItem.path,
196
+ to: subItem.to
197
+ });
198
+ return /*#__PURE__*/ jsx(SidebarMenuSubItem, {
199
+ children: /*#__PURE__*/ jsx(SidebarMenuSubButton, {
200
+ asChild: true,
201
+ isActive: sub.current,
202
+ className: cn("cursor-pointer whitespace-nowrap", subButtonClass),
203
+ children: /*#__PURE__*/ jsx(Link, {
204
+ to: sub.href,
205
+ children: /*#__PURE__*/ jsx(Text, {
206
+ value: subItem.label
195
207
  })
196
208
  })
197
- }, subItem.path);
198
- })
209
+ })
210
+ }, subItem.path);
199
211
  })
200
212
  })
201
- ]
202
- })
203
- }, item.path);
204
- }
213
+ })
214
+ ]
215
+ })
216
+ }, item.path);
205
217
  return /*#__PURE__*/ jsx(SidebarMenuItem, {
206
218
  children: /*#__PURE__*/ jsx(SidebarMenuButton, {
207
219
  tooltip: getTooltipText(item.label),
208
- isActive: active,
220
+ isActive: row.current,
209
221
  asChild: true,
210
222
  className: navButtonClass,
211
223
  children: /*#__PURE__*/ jsxs(Link, {
212
- to: item.path,
224
+ to: row.href,
213
225
  children: [
214
226
  /*#__PURE__*/ jsx(motion.span, {
215
227
  className: "inline-flex items-center justify-center shrink-0",
@@ -252,7 +264,7 @@ function SidebarNav({ companyName, productName, companyLogo, navItems }) {
252
264
  /*#__PURE__*/ jsx("div", {
253
265
  className: "absolute inset-0 pointer-events-none",
254
266
  style: {
255
- boxShadow: "inset -1px 0 0 0 color-mix(in srgb, var(--color-border) 50%, transparent)"
267
+ boxShadow: "inset -1px 0 0 0 color-mix(in srgb, var(--border) 50%, transparent)"
256
268
  }
257
269
  })
258
270
  ]
@@ -1,4 +1,4 @@
1
- import type { TranslationKey } from "./shell-translation-key";
1
+ import type { ShellNavLabel } from "./shell-translation-key";
2
2
  export declare const Text: ({ value }: {
3
- value: TranslationKey;
3
+ value: ShellNavLabel;
4
4
  }) => string | import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { Trans } from "react-i18next";
3
3
  import { VERTEX_NAMESPACE, useVertexTranslation } from "../../lib/vertex-translation.js";
4
+ import { navCatalogFromHook, readNavLabel } from "./shell-nav-label.js";
4
5
  const Text = ({ value })=>{
5
- const { t } = useVertexTranslation();
6
- if ("string" == typeof value) return t(value);
6
+ const { i18n } = useVertexTranslation();
7
+ if ("string" == typeof value) return readNavLabel(navCatalogFromHook(i18n), value);
7
8
  return /*#__PURE__*/ jsx(Trans, {
8
9
  ns: VERTEX_NAMESPACE,
9
10
  i18nKey: value.i18nKey,
@@ -5,3 +5,8 @@ export type TranslationKey = {
5
5
  values: Record<string, string | number | string[]>;
6
6
  components: Record<string, ReactElement>;
7
7
  } | ParseKeys;
8
+ type TranslationObject = Extract<TranslationKey, {
9
+ i18nKey: ParseKeys;
10
+ }>;
11
+ export type ShellNavLabel = string | TranslationObject;
12
+ export {};