@wallarm-org/design-system 1.23.3-rc-fix-remote-shell-breadcrumb-transition.3 → 1.25.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 (49) hide show
  1. package/dist/components/AppShell/story-content/_storyAccountDropdown.d.ts +4 -1
  2. package/dist/components/AppShell/story-content/_storyAccountDropdown.js +64 -56
  3. package/dist/components/AppShell/story-content/_storyConfigRenderer.d.ts +4 -1
  4. package/dist/components/AppShell/story-content/_storyConfigRenderer.js +8 -5
  5. package/dist/components/AppShell/story-content/index.d.ts +1 -1
  6. package/dist/components/AppShell/story-content/index.js +1 -1
  7. package/dist/components/DropdownMenu/DropdownMenuRadioItem.js +1 -1
  8. package/dist/components/NavPanel/NavPanelBack.js +1 -1
  9. package/dist/components/NavPanel/NavPanelGroupLabel.js +1 -1
  10. package/dist/components/NavPanel/NavPanelSkeleton.js +1 -1
  11. package/dist/components/NavPanel/classes.js +4 -4
  12. package/dist/components/NavRail/NavRail.d.ts +7 -0
  13. package/dist/components/NavRail/NavRail.js +5 -3
  14. package/dist/components/NavRail/NavRailBody.js +6 -1
  15. package/dist/components/NavRail/NavRailContext.d.ts +2 -1
  16. package/dist/components/NavRail/NavRailContext.js +1 -1
  17. package/dist/components/NavRail/NavRailFooter.js +6 -1
  18. package/dist/components/NavRail/NavRailItem.d.ts +4 -0
  19. package/dist/components/NavRail/NavRailItem.js +31 -6
  20. package/dist/components/NavRail/NavRailSkeleton.js +24 -4
  21. package/dist/components/NavRail/classes.d.ts +12 -1
  22. package/dist/components/NavRail/classes.js +48 -7
  23. package/dist/components/NavRail/index.d.ts +1 -1
  24. package/dist/components/RemoteShell/NavPanelContent.d.ts +0 -5
  25. package/dist/components/RemoteShell/NavPanelContent.js +4 -6
  26. package/dist/components/RemoteShell/RemoteShell.js +3 -5
  27. package/dist/components/RemoteShell/RemoteShellPanel.js +4 -10
  28. package/dist/components/RemoteShell/model/index.d.ts +1 -1
  29. package/dist/components/RemoteShell/model/index.js +1 -1
  30. package/dist/components/RemoteShell/model/useDrillTransition.d.ts +1 -3
  31. package/dist/components/RemoteShell/model/useDrillTransition.js +11 -17
  32. package/dist/components/RemoteShell/model/useLocationPathname.d.ts +0 -2
  33. package/dist/components/RemoteShell/model/useLocationPathname.js +1 -4
  34. package/dist/components/SearchModal/SearchModal.js +1 -0
  35. package/dist/components/Skeleton/Skeleton.d.ts +1 -1
  36. package/dist/components/Skeleton/Skeleton.js +1 -0
  37. package/dist/components/SplashScreen/SplashScreen.js +17 -5
  38. package/dist/components/SplashScreen/index.d.ts +1 -1
  39. package/dist/components/SplashScreen/lib.d.ts +1 -1
  40. package/dist/components/SplashScreen/lib.js +7 -2
  41. package/dist/components/SplashScreen/types.d.ts +2 -1
  42. package/dist/components/SplashScreen/useContentHeight.d.ts +13 -0
  43. package/dist/components/SplashScreen/useContentHeight.js +33 -0
  44. package/dist/components/SplashScreen/useSplashPhase.d.ts +1 -1
  45. package/dist/components/SplashScreen/useSplashPhase.js +8 -2
  46. package/dist/index.d.ts +1 -1
  47. package/dist/metadata/components.json +52 -11
  48. package/dist/theme/radius.css +1 -0
  49. package/package.json +1 -1
@@ -1,5 +1,8 @@
1
+ import { type NavRailMode } from '../../NavRail';
1
2
  import type { Theme } from '../../ThemeProvider';
2
- export type SidebarMode = 'adaptive' | 'expanded';
3
+ export type SidebarMode = 'adaptive' | 'expanded' | 'collapsed' | 'compact';
4
+ /** Adaptive collapses the rail inside a product and expands it on Home; the other modes pin it. */
5
+ export declare const railModeFor: (mode: SidebarMode, onHome: boolean) => NavRailMode;
3
6
  export declare const AccountDropdown: ({ sidebarMode, onSidebarModeChange, theme, onThemeChange, }: {
4
7
  sidebarMode: SidebarMode;
5
8
  onSidebarModeChange: (mode: SidebarMode) => void;
@@ -1,18 +1,42 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { Check, LogOut, PanelLeftDashed, PencilRuler, Settings, User } from "../../../icons/index.js";
3
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, DropdownMenuTriggerItem } from "../../DropdownMenu/index.js";
2
+ import { Fragment } from "react";
3
+ import { LogOut, PanelLeftDashed, PencilRuler, Settings, User, UserRound } from "../../../icons/index.js";
4
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuTriggerItem } from "../../DropdownMenu/index.js";
4
5
  import { NavRailItem } from "../../NavRail/index.js";
5
6
  import { HStack, VStack } from "../../Stack/index.js";
6
7
  import { Text } from "../../Text/index.js";
8
+ const railModeFor = (mode, onHome)=>{
9
+ if ('adaptive' === mode) return onHome ? 'expanded' : 'collapsed';
10
+ return mode;
11
+ };
7
12
  const USER_NAME = 'Meow Meow';
8
13
  const USER_EMAIL = 'meow@meow.com';
14
+ const THEMES = [
15
+ 'light',
16
+ 'dark'
17
+ ];
18
+ const SIDEBAR_MODE_GROUPS = [
19
+ [
20
+ 'adaptive'
21
+ ],
22
+ [
23
+ 'expanded',
24
+ 'collapsed'
25
+ ],
26
+ [
27
+ 'compact'
28
+ ]
29
+ ];
30
+ const SIDEBAR_MODES = SIDEBAR_MODE_GROUPS.flat();
9
31
  const THEME_LABELS = {
10
32
  light: 'Light',
11
33
  dark: 'Dark'
12
34
  };
13
35
  const SIDEBAR_MODE_LABELS = {
14
36
  adaptive: 'Adaptive',
15
- expanded: 'Always expanded'
37
+ expanded: 'Always expanded',
38
+ collapsed: 'Always collapsed',
39
+ compact: 'Compact'
16
40
  };
17
41
  const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChange })=>/*#__PURE__*/ jsxs(DropdownMenu, {
18
42
  positioning: {
@@ -25,8 +49,9 @@ const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChang
25
49
  children: [
26
50
  /*#__PURE__*/ jsx(DropdownMenuTrigger, {
27
51
  children: /*#__PURE__*/ jsx(NavRailItem, {
28
- icon: User,
29
- label: USER_NAME
52
+ icon: UserRound,
53
+ label: USER_NAME,
54
+ avatar: true
30
55
  })
31
56
  }),
32
57
  /*#__PURE__*/ jsxs(DropdownMenuContent, {
@@ -79,7 +104,7 @@ const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChang
79
104
  /*#__PURE__*/ jsxs(DropdownMenuItemContent, {
80
105
  children: [
81
106
  /*#__PURE__*/ jsx(DropdownMenuItemText, {
82
- children: "Theme"
107
+ children: "Appearance"
83
108
  }),
84
109
  /*#__PURE__*/ jsx(Text, {
85
110
  size: "xs",
@@ -90,32 +115,21 @@ const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChang
90
115
  })
91
116
  ]
92
117
  }),
93
- /*#__PURE__*/ jsxs(DropdownMenuContent, {
118
+ /*#__PURE__*/ jsx(DropdownMenuContent, {
94
119
  className: "w-132",
95
- children: [
96
- /*#__PURE__*/ jsxs(DropdownMenuItem, {
97
- onSelect: ()=>onThemeChange('light'),
98
- children: [
99
- /*#__PURE__*/ jsx(DropdownMenuItemText, {
100
- children: "Light"
101
- }),
102
- 'light' === theme && /*#__PURE__*/ jsx(DropdownMenuShortcut, {
103
- children: /*#__PURE__*/ jsx(Check, {})
120
+ children: /*#__PURE__*/ jsx(DropdownMenuRadioGroup, {
121
+ value: theme,
122
+ onValueChange: ({ value })=>{
123
+ const next = THEMES.find((t)=>t === value);
124
+ if (next) onThemeChange(next);
125
+ },
126
+ children: THEMES.map((t)=>/*#__PURE__*/ jsx(DropdownMenuRadioItem, {
127
+ value: t,
128
+ children: /*#__PURE__*/ jsx(DropdownMenuItemText, {
129
+ children: THEME_LABELS[t]
104
130
  })
105
- ]
106
- }),
107
- /*#__PURE__*/ jsxs(DropdownMenuItem, {
108
- onSelect: ()=>onThemeChange('dark'),
109
- children: [
110
- /*#__PURE__*/ jsx(DropdownMenuItemText, {
111
- children: "Dark"
112
- }),
113
- 'dark' === theme && /*#__PURE__*/ jsx(DropdownMenuShortcut, {
114
- children: /*#__PURE__*/ jsx(Check, {})
115
- })
116
- ]
117
- })
118
- ]
131
+ }, t))
132
+ })
119
133
  })
120
134
  ]
121
135
  }),
@@ -140,32 +154,26 @@ const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChang
140
154
  })
141
155
  ]
142
156
  }),
143
- /*#__PURE__*/ jsxs(DropdownMenuContent, {
157
+ /*#__PURE__*/ jsx(DropdownMenuContent, {
144
158
  className: "w-200",
145
- children: [
146
- /*#__PURE__*/ jsxs(DropdownMenuItem, {
147
- onSelect: ()=>onSidebarModeChange('adaptive'),
148
- children: [
149
- /*#__PURE__*/ jsx(DropdownMenuItemText, {
150
- children: "Adaptive"
151
- }),
152
- 'adaptive' === sidebarMode && /*#__PURE__*/ jsx(DropdownMenuShortcut, {
153
- children: /*#__PURE__*/ jsx(Check, {})
154
- })
155
- ]
156
- }),
157
- /*#__PURE__*/ jsxs(DropdownMenuItem, {
158
- onSelect: ()=>onSidebarModeChange('expanded'),
159
- children: [
160
- /*#__PURE__*/ jsx(DropdownMenuItemText, {
161
- children: "Always expanded"
162
- }),
163
- 'expanded' === sidebarMode && /*#__PURE__*/ jsx(DropdownMenuShortcut, {
164
- children: /*#__PURE__*/ jsx(Check, {})
165
- })
166
- ]
167
- })
168
- ]
159
+ children: /*#__PURE__*/ jsx(DropdownMenuRadioGroup, {
160
+ value: sidebarMode,
161
+ onValueChange: ({ value })=>{
162
+ const next = SIDEBAR_MODES.find((m)=>m === value);
163
+ if (next) onSidebarModeChange(next);
164
+ },
165
+ children: SIDEBAR_MODE_GROUPS.map((group, index)=>/*#__PURE__*/ jsxs(Fragment, {
166
+ children: [
167
+ index > 0 && /*#__PURE__*/ jsx(DropdownMenuSeparator, {}),
168
+ group.map((m)=>/*#__PURE__*/ jsx(DropdownMenuRadioItem, {
169
+ value: m,
170
+ children: /*#__PURE__*/ jsx(DropdownMenuItemText, {
171
+ children: SIDEBAR_MODE_LABELS[m]
172
+ })
173
+ }, m))
174
+ ]
175
+ }, group.join('-')))
176
+ })
169
177
  })
170
178
  ]
171
179
  }),
@@ -184,4 +192,4 @@ const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChang
184
192
  })
185
193
  ]
186
194
  });
187
- export { AccountDropdown };
195
+ export { AccountDropdown, railModeFor };
@@ -3,7 +3,10 @@ import { type Product } from './_storyLib';
3
3
  export interface ConfigRemoteProps {
4
4
  config: NavConfig;
5
5
  basePath?: string;
6
+ /** Fake a 2s load whenever the product changes, to show the panel and content skeletons. */
7
+ simulateLoading?: boolean;
6
8
  }
7
- export declare const RemoteForProduct: ({ product }: {
9
+ export declare const RemoteForProduct: ({ product, simulateLoading, }: {
8
10
  product: Product;
11
+ simulateLoading?: boolean;
9
12
  }) => import("react").JSX.Element;
@@ -31,16 +31,18 @@ const RemotePageContent = ()=>{
31
31
  ]
32
32
  });
33
33
  };
34
- const ConfigRemote = ({ config, basePath })=>{
35
- const [loading, setLoading] = useState(true);
34
+ const ConfigRemote = ({ config, basePath, simulateLoading = true })=>{
35
+ const [loading, setLoading] = useState(simulateLoading);
36
36
  useEffect(()=>{
37
+ if (!simulateLoading) return;
37
38
  setLoading(true);
38
39
  const timer = setTimeout(()=>{
39
40
  setLoading(false);
40
41
  }, 2000);
41
42
  return ()=>clearTimeout(timer);
42
43
  }, [
43
- config.productLabel
44
+ config.productLabel,
45
+ simulateLoading
44
46
  ]);
45
47
  return /*#__PURE__*/ jsx(RemoteShell, {
46
48
  config: config,
@@ -67,12 +69,13 @@ const ConfigRemote = ({ config, basePath })=>{
67
69
  })
68
70
  });
69
71
  };
70
- const RemoteForProduct = ({ product })=>{
72
+ const RemoteForProduct = ({ product, simulateLoading = true })=>{
71
73
  if ('home' === product) return /*#__PURE__*/ jsx(HomeContent, {});
72
74
  const { config } = PRODUCT_CONFIGS[product];
73
75
  return /*#__PURE__*/ jsx(ConfigRemote, {
74
76
  config: config,
75
- basePath: `/${product}`
77
+ basePath: `/${product}`,
78
+ simulateLoading: simulateLoading
76
79
  });
77
80
  };
78
81
  export { RemoteForProduct };
@@ -1,4 +1,4 @@
1
- export { AccountDropdown, type SidebarMode } from './_storyAccountDropdown';
1
+ export { AccountDropdown, railModeFor, type SidebarMode } from './_storyAccountDropdown';
2
2
  export { RemoteForProduct } from './_storyConfigRenderer';
3
3
  export { HeaderActions } from './_storyHeaderActions';
4
4
  export { HomeContent } from './_storyHomeContent';
@@ -1,4 +1,4 @@
1
- export { AccountDropdown } from "./_storyAccountDropdown.js";
1
+ export { AccountDropdown, railModeFor } from "./_storyAccountDropdown.js";
2
2
  export { RemoteForProduct } from "./_storyConfigRenderer.js";
3
3
  export { HeaderActions } from "./_storyHeaderActions.js";
4
4
  export { HomeContent } from "./_storyHomeContent.js";
@@ -15,7 +15,7 @@ const DropdownMenuRadioItem = ({ children, value, disabled, closeOnSelect, varia
15
15
  "data-testid": testId,
16
16
  className: cn(dropdownMenuItemVariants({
17
17
  variant
18
- }), className),
18
+ }), 'data-[state=checked]:bg-states-primary-active', className),
19
19
  children: [
20
20
  children,
21
21
  /*#__PURE__*/ jsx(DropdownMenuItemIndicator, {
@@ -11,7 +11,7 @@ const NavPanelBack = ({ ref, className, children, ...props })=>{
11
11
  type: "button",
12
12
  "data-slot": "nav-panel-back",
13
13
  "data-testid": testId,
14
- className: cn('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-6 p-8 text-sm text-text-primary opacity-85 transition-colors outline-none hover:opacity-100 hover:overlay-states-primary-hover focus-visible:opacity-100 focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed', className),
14
+ className: cn('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-10 p-8 text-sm text-text-primary transition-colors outline-none hover:overlay-states-primary-hover focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed', className),
15
15
  children: [
16
16
  /*#__PURE__*/ jsx(CornerUpLeft, {
17
17
  size: "md"
@@ -22,7 +22,7 @@ const NavPanelGroupLabel = ({ ref, icon: Icon, className, children, ...props })=
22
22
  style: {
23
23
  paddingLeft: 8 + depth * indent
24
24
  },
25
- className: cn('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-6 py-8 pr-8 text-sm text-text-primary opacity-85 transition-colors outline-none hover:opacity-100 hover:overlay-states-primary-hover focus-visible:opacity-100 focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed', className),
25
+ className: cn('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-10 py-8 pr-8 text-sm text-text-primary transition-colors outline-none hover:overlay-states-primary-hover focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed', className),
26
26
  children: [
27
27
  Icon && /*#__PURE__*/ jsx("span", {
28
28
  className: "flex shrink-0 items-center justify-center",
@@ -15,7 +15,7 @@ const NavPanelSkeleton = ({ ref, className, count = 6, ...props })=>{
15
15
  }, (_, i)=>/*#__PURE__*/ jsx(Skeleton, {
16
16
  width: "100%",
17
17
  height: "28px",
18
- rounded: 6
18
+ rounded: 10
19
19
  }, i))
20
20
  });
21
21
  };
@@ -1,20 +1,20 @@
1
1
  import { cva } from "class-variance-authority";
2
- const navPanelItemVariants = cva('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-6 p-8 text-sm text-text-primary transition-colors outline-none', {
2
+ const navPanelItemVariants = cva('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-10 p-8 text-sm text-text-primary transition-colors outline-none', {
3
3
  variants: {
4
4
  active: {
5
5
  true: 'overlay-states-primary-active font-semibold',
6
- false: 'opacity-85 hover:opacity-100 hover:overlay-states-primary-hover focus-visible:opacity-100 focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed'
6
+ false: 'hover:overlay-states-primary-hover focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed'
7
7
  }
8
8
  },
9
9
  defaultVariants: {
10
10
  active: false
11
11
  }
12
12
  });
13
- const navPanelGroupItemVariants = cva('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-6 py-8 pr-8 text-sm text-text-primary transition-colors outline-none', {
13
+ const navPanelGroupItemVariants = cva('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-10 py-8 pr-8 text-sm text-text-primary transition-colors outline-none', {
14
14
  variants: {
15
15
  active: {
16
16
  true: 'overlay-states-primary-active font-semibold',
17
- false: 'opacity-85 hover:opacity-100 hover:overlay-states-primary-hover focus-visible:opacity-100 focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed'
17
+ false: 'hover:overlay-states-primary-hover focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed'
18
18
  }
19
19
  },
20
20
  defaultVariants: {
@@ -1,8 +1,15 @@
1
1
  import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
2
2
  import { type TestableProps } from '../../utils/testId';
3
+ import { type NavRailMode } from './NavRailContext';
3
4
  export interface NavRailProps extends HTMLAttributes<HTMLElement>, TestableProps {
4
5
  ref?: Ref<HTMLElement>;
5
6
  children?: ReactNode;
7
+ /**
8
+ * How the rail lays out its items: `expanded` (icon beside label), `collapsed` (icon only) or
9
+ * `compact` (icon over a short label). Wins over `collapsed` when both are set.
10
+ */
11
+ mode?: NavRailMode;
12
+ /** Shorthand for `mode='collapsed'`, kept so existing hosts keep working. Prefer `mode`. */
6
13
  collapsed?: boolean;
7
14
  }
8
15
  export declare const NavRail: FC<NavRailProps>;
@@ -6,8 +6,9 @@ import { cn } from "../../utils/cn.js";
6
6
  import { TestIdProvider } from "../../utils/testId.js";
7
7
  import { navRailVariants } from "./classes.js";
8
8
  import { NavRailContextProvider } from "./NavRailContext.js";
9
- const NavRail = ({ ref, collapsed = false, className, children, 'data-testid': testId, ...props })=>{
9
+ const NavRail = ({ ref, mode: modeProp, collapsed = false, className, children, 'data-testid': testId, ...props })=>{
10
10
  const internalRef = useRef(null);
11
+ const mode = modeProp ?? (collapsed ? 'collapsed' : 'expanded');
11
12
  const focusPanel = useCallback(()=>{
12
13
  const panel = document.querySelector('[data-slot="nav-panel"]');
13
14
  const target = panel?.querySelector('[tabindex="0"]');
@@ -37,16 +38,17 @@ const NavRail = ({ ref, collapsed = false, className, children, 'data-testid': t
37
38
  value: testId,
38
39
  children: /*#__PURE__*/ jsx(NavRailContextProvider, {
39
40
  value: {
40
- collapsed
41
+ mode
41
42
  },
42
43
  children: /*#__PURE__*/ jsx("nav", {
43
44
  ...props,
44
45
  ref: composeRefs(internalRef, ref),
45
46
  "aria-label": "Global navigation",
46
47
  "data-slot": "nav-rail",
48
+ "data-mode": mode,
47
49
  "data-testid": testId,
48
50
  className: cn(navRailVariants({
49
- collapsed
51
+ mode
50
52
  }), className),
51
53
  children: children
52
54
  })
@@ -1,14 +1,19 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../../utils/cn.js";
3
3
  import { useTestId } from "../../utils/testId.js";
4
+ import { navRailBodyVariants } from "./classes.js";
5
+ import { useNavRailContext } from "./NavRailContext.js";
4
6
  const NavRailBody = ({ ref, className, children, ...props })=>{
7
+ const { mode } = useNavRailContext();
5
8
  const testId = useTestId('body');
6
9
  return /*#__PURE__*/ jsx("div", {
7
10
  ...props,
8
11
  ref: ref,
9
12
  "data-slot": "nav-rail-body",
10
13
  "data-testid": testId,
11
- className: cn('flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto overscroll-none [scrollbar-width:thin]', className),
14
+ className: cn(navRailBodyVariants({
15
+ mode
16
+ }), className),
12
17
  children: children
13
18
  });
14
19
  };
@@ -1,5 +1,6 @@
1
+ export type NavRailMode = 'expanded' | 'collapsed' | 'compact';
1
2
  interface NavRailContextValue {
2
- collapsed: boolean;
3
+ mode: NavRailMode;
3
4
  }
4
5
  export declare const NavRailContextProvider: import("react").Provider<NavRailContextValue>;
5
6
  export declare function useNavRailContext(): NavRailContextValue;
@@ -1,6 +1,6 @@
1
1
  import { createContext, useContext } from "react";
2
2
  const NavRailCtx = /*#__PURE__*/ createContext({
3
- collapsed: false
3
+ mode: 'expanded'
4
4
  });
5
5
  const NavRailContextProvider = NavRailCtx.Provider;
6
6
  function useNavRailContext() {
@@ -1,14 +1,19 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../../utils/cn.js";
3
3
  import { useTestId } from "../../utils/testId.js";
4
+ import { navRailFooterVariants } from "./classes.js";
5
+ import { useNavRailContext } from "./NavRailContext.js";
4
6
  const NavRailFooter = ({ ref, className, children, ...props })=>{
7
+ const { mode } = useNavRailContext();
5
8
  const testId = useTestId('footer');
6
9
  return /*#__PURE__*/ jsx("div", {
7
10
  ...props,
8
11
  ref: ref,
9
12
  "data-slot": "nav-rail-footer",
10
13
  "data-testid": testId,
11
- className: cn('mt-auto flex flex-col gap-2', className),
14
+ className: cn(navRailFooterVariants({
15
+ mode
16
+ }), className),
12
17
  children: children
13
18
  });
14
19
  };
@@ -8,5 +8,9 @@ export interface NavRailItemProps extends AnchorHTMLAttributes<HTMLAnchorElement
8
8
  label: ReactNode;
9
9
  shortcut?: string[];
10
10
  active?: boolean;
11
+ /** Seats the icon on a soft plate, for the signed-in user's item at the foot of the rail. */
12
+ avatar?: boolean;
13
+ /** User photo for the plate (implies `avatar`). The icon stays underneath and returns if the photo fails to load. */
14
+ avatarSrc?: string;
11
15
  }
12
16
  export declare const NavRailItem: FC<NavRailItemProps>;
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { Fragment, useRef } from "react";
2
+ import { Fragment, useRef, useState } from "react";
3
3
  import { composeRefs } from "@radix-ui/react-compose-refs";
4
4
  import { Slot, Slottable } from "@radix-ui/react-slot";
5
5
  import { cn } from "../../utils/cn.js";
@@ -8,35 +8,60 @@ import { Kbd } from "../Kbd/index.js";
8
8
  import { Tooltip } from "../Tooltip/index.js";
9
9
  import { TooltipContent } from "../Tooltip/TooltipContent.js";
10
10
  import { TooltipTrigger } from "../Tooltip/TooltipTrigger.js";
11
- import { navRailItemVariants } from "./classes.js";
11
+ import { navRailItemCompactLabelClassName, navRailItemVariants } from "./classes.js";
12
12
  import { useNavRailContext } from "./NavRailContext.js";
13
13
  import { useShortcut } from "./useShortcut.js";
14
- const NavRailItem = ({ ref, asChild = false, icon: Icon, label, shortcut, active = false, className, children, 'data-testid': testIdProp, ...props })=>{
15
- const { collapsed } = useNavRailContext();
14
+ const NavRailItem = ({ ref, asChild = false, icon: Icon, label, shortcut, active = false, avatar = false, avatarSrc, className, children, 'data-testid': testIdProp, ...props })=>{
15
+ const { mode } = useNavRailContext();
16
16
  const testId = useTestId('item', testIdProp);
17
17
  const Comp = asChild ? Slot : 'a';
18
18
  const internalRef = useRef(null);
19
+ const [failedSrc, setFailedSrc] = useState();
20
+ const photo = avatarSrc && avatarSrc !== failedSrc ? avatarSrc : void 0;
21
+ const hasPlate = avatar || void 0 !== avatarSrc;
22
+ const showsLabel = 'expanded' === mode || 'compact' === mode && !hasPlate;
23
+ const fallbackName = showsLabel || 'string' != typeof label ? void 0 : label;
19
24
  useShortcut(shortcut, internalRef);
20
25
  const element = /*#__PURE__*/ jsxs(Comp, {
21
26
  ...props,
22
27
  ref: composeRefs(internalRef, ref),
28
+ "aria-label": props['aria-label'] ?? fallbackName,
23
29
  "aria-current": active ? 'page' : void 0,
24
30
  "data-slot": "nav-rail-item",
25
31
  "data-testid": testId,
26
32
  className: cn(navRailItemVariants({
33
+ mode,
27
34
  active
28
35
  }), className),
29
36
  children: [
30
37
  /*#__PURE__*/ jsx("span", {
31
38
  className: "flex shrink-0 items-center justify-center",
32
- children: /*#__PURE__*/ jsx(Icon, {
39
+ children: hasPlate ? /*#__PURE__*/ jsxs("span", {
40
+ "data-slot": "nav-rail-item-avatar",
41
+ className: cn('-m-4 grid size-24 place-items-center overflow-hidden rounded-8 bg-states-primary-hover *:col-start-1 *:row-start-1', !photo && 'border border-border-primary'),
42
+ children: [
43
+ /*#__PURE__*/ jsx(Icon, {
44
+ size: "md"
45
+ }),
46
+ photo && /*#__PURE__*/ jsx("img", {
47
+ src: photo,
48
+ alt: "",
49
+ className: "size-full object-cover",
50
+ onError: ()=>setFailedSrc(photo)
51
+ })
52
+ ]
53
+ }) : /*#__PURE__*/ jsx(Icon, {
33
54
  size: "md"
34
55
  })
35
56
  }),
36
- !collapsed && /*#__PURE__*/ jsx("span", {
57
+ 'expanded' === mode && /*#__PURE__*/ jsx("span", {
37
58
  className: cn('truncate whitespace-nowrap transition-[opacity,width] duration-200 pl-8'),
38
59
  children: label
39
60
  }),
61
+ showsLabel && 'compact' === mode && /*#__PURE__*/ jsx("span", {
62
+ className: navRailItemCompactLabelClassName,
63
+ children: label
64
+ }),
40
65
  /*#__PURE__*/ jsx(Slottable, {
41
66
  children: children
42
67
  })
@@ -2,20 +2,40 @@ import { jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../../utils/cn.js";
3
3
  import { useTestId } from "../../utils/testId.js";
4
4
  import { Skeleton } from "../Skeleton/index.js";
5
+ import { navRailSkeletonVariants } from "./classes.js";
6
+ import { useNavRailContext } from "./NavRailContext.js";
7
+ const SKELETON_BARS = {
8
+ expanded: {
9
+ width: '100%',
10
+ height: '28px'
11
+ },
12
+ collapsed: {
13
+ width: '28px',
14
+ height: '28px'
15
+ },
16
+ compact: {
17
+ width: '54px',
18
+ height: '38px'
19
+ }
20
+ };
5
21
  const NavRailSkeleton = ({ ref, className, count = 4, ...props })=>{
22
+ const { mode } = useNavRailContext();
6
23
  const testId = useTestId('skeleton');
24
+ const bar = SKELETON_BARS[mode];
7
25
  return /*#__PURE__*/ jsx("div", {
8
26
  ...props,
9
27
  ref: ref,
10
28
  "data-slot": "nav-rail-skeleton",
11
29
  "data-testid": testId,
12
- className: cn('flex flex-col gap-6', className),
30
+ className: cn(navRailSkeletonVariants({
31
+ mode
32
+ }), className),
13
33
  children: Array.from({
14
34
  length: count
15
35
  }, (_, i)=>/*#__PURE__*/ jsx(Skeleton, {
16
- width: "100%",
17
- height: "28px",
18
- rounded: 6
36
+ width: bar.width,
37
+ height: bar.height,
38
+ rounded: 10
19
39
  }, i))
20
40
  });
21
41
  };
@@ -1,6 +1,17 @@
1
1
  export declare const navRailVariants: (props?: ({
2
- collapsed?: boolean | null | undefined;
2
+ mode?: "collapsed" | "compact" | "expanded" | null | undefined;
3
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
4
+ export declare const navRailBodyVariants: (props?: ({
5
+ mode?: "collapsed" | "compact" | "expanded" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ export declare const navRailFooterVariants: (props?: ({
8
+ mode?: "collapsed" | "compact" | "expanded" | null | undefined;
9
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
10
+ export declare const navRailSkeletonVariants: (props?: ({
11
+ mode?: "collapsed" | "compact" | "expanded" | null | undefined;
3
12
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
4
13
  export declare const navRailItemVariants: (props?: ({
14
+ mode?: "collapsed" | "compact" | "expanded" | null | undefined;
5
15
  active?: boolean | null | undefined;
6
16
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
17
+ export declare const navRailItemCompactLabelClassName = "line-clamp-2 w-56 shrink-0 text-center text-2xs font-medium text-ellipsis break-normal";