@redis-ui/components 47.0.1 → 47.2.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 (45) hide show
  1. package/dist/SideBar/SideBar.cjs +5 -2
  2. package/dist/SideBar/SideBar.d.ts +5 -1
  3. package/dist/SideBar/SideBar.js +5 -2
  4. package/dist/SideBar/SideBar.style.cjs +4 -4
  5. package/dist/SideBar/SideBar.style.d.ts +3 -3
  6. package/dist/SideBar/SideBar.style.js +4 -4
  7. package/dist/SideBar/SideBar.types.d.ts +1 -0
  8. package/dist/SideBar/components/Group/Group.cjs +7 -0
  9. package/dist/SideBar/components/Group/Group.d.ts +5 -0
  10. package/dist/SideBar/components/Group/Group.js +6 -0
  11. package/dist/SideBar/components/Group/Group.types.d.ts +2 -0
  12. package/dist/SideBar/components/Group/Group.types.js +1 -0
  13. package/dist/SideBar/components/Group/components/Title/Title.cjs +20 -0
  14. package/dist/SideBar/components/Group/components/Title/Title.d.ts +3 -0
  15. package/dist/SideBar/components/Group/components/Title/Title.js +19 -0
  16. package/dist/SideBar/components/Group/components/Title/Title.style.cjs +25 -0
  17. package/dist/SideBar/components/Group/components/Title/Title.style.d.ts +5 -0
  18. package/dist/SideBar/components/Group/components/Title/Title.style.js +22 -0
  19. package/dist/SideBar/components/Group/components/Title/Title.types.d.ts +4 -0
  20. package/dist/SideBar/components/Group/components/Title/Title.types.js +1 -0
  21. package/dist/SideBar/components/Item/Item.cjs +3 -1
  22. package/dist/SideBar/components/Item/Item.d.ts +1 -0
  23. package/dist/SideBar/components/Item/Item.js +3 -1
  24. package/dist/SideBar/components/Item/Item.style.cjs +17 -4
  25. package/dist/SideBar/components/Item/Item.style.js +17 -4
  26. package/dist/SideBar/components/Item/components/Badge/Badge.cjs +18 -0
  27. package/dist/SideBar/components/Item/components/Badge/Badge.d.ts +4 -0
  28. package/dist/SideBar/components/Item/components/Badge/Badge.js +16 -0
  29. package/dist/SideBar/components/Item/components/Badge/Badge.style.cjs +11 -0
  30. package/dist/SideBar/components/Item/components/Badge/Badge.style.d.ts +4 -0
  31. package/dist/SideBar/components/Item/components/Badge/Badge.style.js +9 -0
  32. package/dist/SideBar/components/Item/components/Button/Button.cjs +11 -4
  33. package/dist/SideBar/components/Item/components/Button/Button.js +11 -4
  34. package/dist/SideBar/components/Item/components/Button/Button.style.cjs +6 -1
  35. package/dist/SideBar/components/Item/components/Button/Button.style.d.ts +4 -1
  36. package/dist/SideBar/components/Item/components/Button/Button.style.js +6 -1
  37. package/dist/SideBar/components/Item/components/Text/Text.cjs +12 -6
  38. package/dist/SideBar/components/Item/components/Text/Text.js +12 -6
  39. package/dist/SideBar/components/Item/components/Text/Text.style.cjs +1 -5
  40. package/dist/SideBar/components/Item/components/Text/Text.style.d.ts +4 -1
  41. package/dist/SideBar/components/Item/components/Text/Text.style.js +1 -5
  42. package/dist/SideBar/components/ScrollContainer/ScrollContainer.style.cjs +1 -1
  43. package/dist/SideBar/components/ScrollContainer/ScrollContainer.style.js +1 -1
  44. package/package.json +2 -2
  45. package/skills/redis-ui-components/references/SideBar.md +94 -10
@@ -12,12 +12,13 @@ const require_Button = require("./components/Button/Button.cjs");
12
12
  const require_Header = require("./components/Header/Header.cjs");
13
13
  const require_ScrollContainer = require("./components/ScrollContainer/ScrollContainer.cjs");
14
14
  const require_Footer = require("./components/Footer/Footer.cjs");
15
+ const require_Group = require("./components/Group/Group.cjs");
15
16
  const require_SideBarThemeProvider = require("./SideBarThemeProvider.cjs");
16
17
  let _redislabsdev_redis_ui_styles = require("@redislabsdev/redis-ui-styles");
17
18
  let react_jsx_runtime = require("react/jsx-runtime");
18
19
  let react = require("react");
19
20
  //#region src/SideBar/SideBar.tsx
20
- var SideBar = Object.assign(({ isExpanded, ...rest }) => {
21
+ var SideBar = Object.assign(({ isExpanded, expandedWidth, ...rest }) => {
21
22
  const [transitionEnd, setTransitionEnd] = (0, react.useState)(true);
22
23
  const prefersReducedMotion = (0, _redislabsdev_redis_ui_styles.usePrefersReducedMotion)();
23
24
  const sidebarId = require_index.useId();
@@ -40,6 +41,7 @@ var SideBar = Object.assign(({ isExpanded, ...rest }) => {
40
41
  "data-state": isExpanded ? "expanded" : "collapsed",
41
42
  "data-transition": transitionEnd ? "inactive" : "active",
42
43
  "data-role": "nav-bar",
44
+ $expandedWidth: expandedWidth,
43
45
  ...rest
44
46
  }) })
45
47
  }) });
@@ -52,7 +54,8 @@ var SideBar = Object.assign(({ isExpanded, ...rest }) => {
52
54
  Item: require_Item.default,
53
55
  Button: require_Button.default,
54
56
  Header: require_Header.default,
55
- Footer: require_Footer.default
57
+ Footer: require_Footer.default,
58
+ Group: require_Group.default
56
59
  });
57
60
  //#endregion
58
61
  exports.default = SideBar;
@@ -1,5 +1,5 @@
1
1
  import { SideBarProps } from './SideBar.types';
2
- declare const SideBar: (({ isExpanded, ...rest }: SideBarProps) => import("react/jsx-runtime").JSX.Element) & {
2
+ declare const SideBar: (({ isExpanded, expandedWidth, ...rest }: SideBarProps) => import("react/jsx-runtime").JSX.Element) & {
3
3
  SideBarLogo: ({ logoIcon: LogoIcon, ...restProps }: import("./components/SideBarLogo/SideBarLogo.types").SideBarLogoProps) => import("react/jsx-runtime").JSX.Element;
4
4
  ItemsContainer: (props: import("./components/ItemsContainer/ItemsContainer.types").SideBarItemsContainerProps) => import("react/jsx-runtime").JSX.Element;
5
5
  ScrollContainer: (props: import("./components/ScrollContainer/ScrollContainer.types").SideBarScrollContainerProps) => import("react/jsx-runtime").JSX.Element;
@@ -9,6 +9,7 @@ declare const SideBar: (({ isExpanded, ...rest }: SideBarProps) => import("react
9
9
  Icon: ({ icon: ItemIcon, ...restProps }: import("./components/Item/components/Icon/Icon.types").SideBarItemIconProps) => import("react/jsx-runtime").JSX.Element;
10
10
  Text: (props: import("./components/Item/components/Text/Text.types").SideBarItemTextProps) => import("react/jsx-runtime").JSX.Element;
11
11
  Button: import("react").ForwardRefExoticComponent<import("..").ActionIconButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
12
+ Badge: import("react").ForwardRefExoticComponent<import("..").BadgeProps & import("react").RefAttributes<HTMLDivElement>>;
12
13
  };
13
14
  Button: ({ tooltipProps: { text: tooltipText, placement, ...tooltipProps }, buttonExpandedContent, buttonCollapsedIcon: ButtonCollapsedIcon, ...rest }: import("./components/Button/Button.types").SideBarButtonProps) => import("react/jsx-runtime").JSX.Element;
14
15
  Header: ({ children, onToggle, ...rest }: import("./components/Header/Header.types").SideBarHeaderProps) => import("react/jsx-runtime").JSX.Element;
@@ -17,5 +18,8 @@ declare const SideBar: (({ isExpanded, ...rest }: SideBarProps) => import("react
17
18
  Link: ({ children, ...rest }: import("./components/Footer/components/Link/Link.types").LinkProps) => import("react/jsx-runtime").JSX.Element;
18
19
  Text: (props: import("./components/Footer/components/Text/Text.types").TextProps) => import("react/jsx-runtime").JSX.Element;
19
20
  };
21
+ Group: ((props: import("./components/Group/Group.types").SideBarGroupProps) => import("react/jsx-runtime").JSX.Element) & {
22
+ Title: ({ children, ...rest }: import("./components/Group/components/Title/Title.types").SideBarGroupTitleProps) => import("react/jsx-runtime").JSX.Element;
23
+ };
20
24
  };
21
25
  export default SideBar;
@@ -11,12 +11,13 @@ import Button from "./components/Button/Button.js";
11
11
  import Header from "./components/Header/Header.js";
12
12
  import ScrollContainer from "./components/ScrollContainer/ScrollContainer.js";
13
13
  import Footer from "./components/Footer/Footer.js";
14
+ import Group from "./components/Group/Group.js";
14
15
  import { SideBarThemeProvider } from "./SideBarThemeProvider.js";
15
16
  import { usePrefersReducedMotion } from "@redislabsdev/redis-ui-styles";
16
17
  import { jsx } from "react/jsx-runtime";
17
18
  import { useState } from "react";
18
19
  //#region src/SideBar/SideBar.tsx
19
- var SideBar = Object.assign(({ isExpanded, ...rest }) => {
20
+ var SideBar = Object.assign(({ isExpanded, expandedWidth, ...rest }) => {
20
21
  const [transitionEnd, setTransitionEnd] = useState(true);
21
22
  const prefersReducedMotion = usePrefersReducedMotion();
22
23
  const sidebarId = useId();
@@ -39,6 +40,7 @@ var SideBar = Object.assign(({ isExpanded, ...rest }) => {
39
40
  "data-state": isExpanded ? "expanded" : "collapsed",
40
41
  "data-transition": transitionEnd ? "inactive" : "active",
41
42
  "data-role": "nav-bar",
43
+ $expandedWidth: expandedWidth,
42
44
  ...rest
43
45
  }) })
44
46
  }) });
@@ -51,7 +53,8 @@ var SideBar = Object.assign(({ isExpanded, ...rest }) => {
51
53
  Item,
52
54
  Button,
53
55
  Header,
54
- Footer
56
+ Footer,
57
+ Group
55
58
  });
56
59
  //#endregion
57
60
  export { SideBar as default };
@@ -11,20 +11,20 @@ var useRootStateStyle = (getStyle) => {
11
11
  const { expanded, collapsed } = (0, _redislabsdev_redis_ui_styles.useTheme)().components.sideBar;
12
12
  return styled_components.css`
13
13
  &[data-state='collapsed'] {
14
- ${getStyle(collapsed)}
14
+ ${getStyle(collapsed, "collapsed")}
15
15
  }
16
16
  &[data-state='expanded'] {
17
- ${getStyle(expanded)}
17
+ ${getStyle(expanded, "expanded")}
18
18
  }
19
19
  `;
20
20
  };
21
21
  var SideBarContainer = (0, styled_components.default)(require_FlexGroup.FlexGroup).withConfig({
22
22
  displayName: "SideBarstyle__SideBarContainer",
23
23
  componentId: "RedisUI__sc-suwica-0"
24
- })(["position:relative;height:100%;transition:width 0.6s;@media (prefers-reduced-motion:reduce){transition:none;}", ""], () => useRootStateStyle((theme) => styled_components.css`
24
+ })(["position:relative;height:100%;transition:width 0.6s;@media (prefers-reduced-motion:reduce){transition:none;}", ""], ({ $expandedWidth }) => useRootStateStyle((theme, state) => styled_components.css`
25
25
  box-shadow: ${theme.shadow};
26
26
  background-color: ${theme.bgColor};
27
- width: ${theme.width};
27
+ width: ${(state === "expanded" ? $expandedWidth : void 0) ?? theme.width};
28
28
  border-right: ${theme.borderRight};
29
29
  `));
30
30
  //#endregion
@@ -1,3 +1,3 @@
1
- import { ThemeProps } from 'styled-components/macro';
2
- import { Theme } from '@redislabsdev/redis-ui-styles';
3
- export declare const SideBarContainer: import("styled-components").StyledComponent<({ gap, direction, align, justify, wrap, ...restProps }: import("../Layouts").FlexGroupProps) => import("react/jsx-runtime").JSX.Element, any, ThemeProps<Theme>, never>;
1
+ export declare const SideBarContainer: import("styled-components").StyledComponent<({ gap, direction, align, justify, wrap, ...restProps }: import("../Layouts").FlexGroupProps) => import("react/jsx-runtime").JSX.Element, any, {
2
+ $expandedWidth?: string;
3
+ }, never>;
@@ -9,20 +9,20 @@ var useRootStateStyle = (getStyle) => {
9
9
  const { expanded, collapsed } = useTheme().components.sideBar;
10
10
  return css`
11
11
  &[data-state='collapsed'] {
12
- ${getStyle(collapsed)}
12
+ ${getStyle(collapsed, "collapsed")}
13
13
  }
14
14
  &[data-state='expanded'] {
15
- ${getStyle(expanded)}
15
+ ${getStyle(expanded, "expanded")}
16
16
  }
17
17
  `;
18
18
  };
19
19
  var SideBarContainer = _styled(FlexGroup).withConfig({
20
20
  displayName: "SideBarstyle__SideBarContainer",
21
21
  componentId: "RedisUI__sc-suwica-0"
22
- })(["position:relative;height:100%;transition:width 0.6s;@media (prefers-reduced-motion:reduce){transition:none;}", ""], () => useRootStateStyle((theme) => css`
22
+ })(["position:relative;height:100%;transition:width 0.6s;@media (prefers-reduced-motion:reduce){transition:none;}", ""], ({ $expandedWidth }) => useRootStateStyle((theme, state) => css`
23
23
  box-shadow: ${theme.shadow};
24
24
  background-color: ${theme.bgColor};
25
- width: ${theme.width};
25
+ width: ${(state === "expanded" ? $expandedWidth : void 0) ?? theme.width};
26
26
  border-right: ${theme.borderRight};
27
27
  `));
28
28
  //#endregion
@@ -2,6 +2,7 @@ import { TooltipContentProps } from '../Tooltip/components/Content/Content.types
2
2
  import { FlexGroupProps } from '../Layouts';
3
3
  export interface SideBarProps extends Omit<FlexGroupProps, 'direction'> {
4
4
  isExpanded: boolean;
5
+ expandedWidth?: string;
5
6
  }
6
7
  export interface SideBarContextProps {
7
8
  isExpanded: boolean;
@@ -0,0 +1,7 @@
1
+ require("../../../_virtual/_rolldown/runtime.cjs");
2
+ const require_Title = require("./components/Title/Title.cjs");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ //#region src/SideBar/components/Group/Group.tsx
5
+ var Group = Object.assign((props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { ...props }), { Title: require_Title.default });
6
+ //#endregion
7
+ exports.default = Group;
@@ -0,0 +1,5 @@
1
+ import { SideBarGroupProps } from './Group.types';
2
+ declare const Group: ((props: SideBarGroupProps) => import("react/jsx-runtime").JSX.Element) & {
3
+ Title: ({ children, ...rest }: import("./components/Title/Title.types").SideBarGroupTitleProps) => import("react/jsx-runtime").JSX.Element;
4
+ };
5
+ export default Group;
@@ -0,0 +1,6 @@
1
+ import Title from "./components/Title/Title.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/SideBar/components/Group/Group.tsx
4
+ var Group = Object.assign((props) => /* @__PURE__ */ jsx("div", { ...props }), { Title });
5
+ //#endregion
6
+ export { Group as default };
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export type SideBarGroupProps = React.HTMLAttributes<HTMLDivElement>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ require("../../../../../_virtual/_rolldown/runtime.cjs");
2
+ const require_SideBar_context = require("../../../../SideBar.context.cjs");
3
+ const require_Title_style = require("./Title.style.cjs");
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ //#region src/SideBar/components/Group/components/Title/Title.tsx
6
+ var Title = ({ children, ...rest }) => {
7
+ const { isExpanded, transitionEnd } = require_SideBar_context.useSideBarContext();
8
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Title_style.Container, {
9
+ ...rest,
10
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Title_style.Label, {
11
+ size: "M",
12
+ component: "span",
13
+ $isExpanded: isExpanded,
14
+ $transitionEnd: transitionEnd,
15
+ children
16
+ })
17
+ });
18
+ };
19
+ //#endregion
20
+ exports.default = Title;
@@ -0,0 +1,3 @@
1
+ import { SideBarGroupTitleProps } from './Title.types';
2
+ declare const Title: ({ children, ...rest }: SideBarGroupTitleProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default Title;
@@ -0,0 +1,19 @@
1
+ import { useSideBarContext } from "../../../../SideBar.context.js";
2
+ import { Container, Label } from "./Title.style.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/SideBar/components/Group/components/Title/Title.tsx
5
+ var Title = ({ children, ...rest }) => {
6
+ const { isExpanded, transitionEnd } = useSideBarContext();
7
+ return /* @__PURE__ */ jsx(Container, {
8
+ ...rest,
9
+ children: /* @__PURE__ */ jsx(Label, {
10
+ size: "M",
11
+ component: "span",
12
+ $isExpanded: isExpanded,
13
+ $transitionEnd: transitionEnd,
14
+ children
15
+ })
16
+ });
17
+ };
18
+ //#endregion
19
+ export { Title as default };
@@ -0,0 +1,25 @@
1
+ const require_runtime = require("../../../../../_virtual/_rolldown/runtime.cjs");
2
+ const require_Typography = require("../../../../../Typography/Typography.cjs");
3
+ const require_SideBar_utils = require("../../../../SideBar.utils.cjs");
4
+ let styled_components = require("styled-components");
5
+ styled_components = require_runtime.__toESM(styled_components, 1);
6
+ //#region src/SideBar/components/Group/components/Title/Title.style.ts
7
+ var Container = styled_components.default.div.withConfig({
8
+ displayName: "Titlestyle__Container",
9
+ componentId: "RedisUI__sc-1qd2bt1-0"
10
+ })(["display:block;overflow:hidden;", ""], () => require_SideBar_utils.useStateStyle((theme) => styled_components.css`
11
+ padding: ${theme.groupTitle.padding};
12
+ `));
13
+ var Label = (0, styled_components.default)(require_Typography.default.Body).withConfig({
14
+ displayName: "Titlestyle__Label",
15
+ componentId: "RedisUI__sc-1qd2bt1-1"
16
+ })([
17
+ "display:block;white-space:nowrap;transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:",
18
+ ";",
19
+ ""
20
+ ], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0", () => require_SideBar_utils.useStateStyle((theme) => styled_components.css`
21
+ color: ${theme.groupTitle.textColor};
22
+ `));
23
+ //#endregion
24
+ exports.Container = Container;
25
+ exports.Label = Label;
@@ -0,0 +1,5 @@
1
+ export declare const Container: import("styled-components").StyledComponent<"div", any, {}, never>;
2
+ export declare const Label: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../../../../../Typography").TypographyBodyProps & import("react").RefAttributes<HTMLElement>>, any, {
3
+ $isExpanded: boolean;
4
+ $transitionEnd: boolean;
5
+ }, never>;
@@ -0,0 +1,22 @@
1
+ import Typography from "../../../../../Typography/Typography.js";
2
+ import { useStateStyle } from "../../../../SideBar.utils.js";
3
+ import _styled, { css } from "styled-components";
4
+ //#region src/SideBar/components/Group/components/Title/Title.style.ts
5
+ var Container = _styled.div.withConfig({
6
+ displayName: "Titlestyle__Container",
7
+ componentId: "RedisUI__sc-1qd2bt1-0"
8
+ })(["display:block;overflow:hidden;", ""], () => useStateStyle((theme) => css`
9
+ padding: ${theme.groupTitle.padding};
10
+ `));
11
+ var Label = _styled(Typography.Body).withConfig({
12
+ displayName: "Titlestyle__Label",
13
+ componentId: "RedisUI__sc-1qd2bt1-1"
14
+ })([
15
+ "display:block;white-space:nowrap;transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:",
16
+ ";",
17
+ ""
18
+ ], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0", () => useStateStyle((theme) => css`
19
+ color: ${theme.groupTitle.textColor};
20
+ `));
21
+ //#endregion
22
+ export { Container, Label };
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export interface SideBarGroupTitleProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
3
+ children: React.ReactNode;
4
+ }
@@ -4,6 +4,7 @@ const require_SideBar_context = require("../../SideBar.context.cjs");
4
4
  const require_Icon = require("./components/Icon/Icon.cjs");
5
5
  const require_Text = require("./components/Text/Text.cjs");
6
6
  const require_Button = require("./components/Button/Button.cjs");
7
+ const require_Badge = require("./components/Badge/Badge.cjs");
7
8
  const require_Item_style = require("./Item.style.cjs");
8
9
  let react_jsx_runtime = require("react/jsx-runtime");
9
10
  let react = require("react");
@@ -39,7 +40,8 @@ var Item = Object.assign(({ tooltipProps, isActive = false, onKeyDown, ...restPr
39
40
  }, {
40
41
  Icon: require_Icon.default,
41
42
  Text: require_Text.default,
42
- Button: require_Button.default
43
+ Button: require_Button.default,
44
+ Badge: require_Badge.default
43
45
  });
44
46
  //#endregion
45
47
  exports.default = Item;
@@ -3,5 +3,6 @@ declare const Item: (({ tooltipProps, isActive, onKeyDown, ...restProps }: SideB
3
3
  Icon: ({ icon: ItemIcon, ...restProps }: import("./components/Icon/Icon.types").SideBarItemIconProps) => import("react/jsx-runtime").JSX.Element;
4
4
  Text: (props: import("./components/Text/Text.types").SideBarItemTextProps) => import("react/jsx-runtime").JSX.Element;
5
5
  Button: import("react").ForwardRefExoticComponent<import("../../..").ActionIconButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
6
+ Badge: import("react").ForwardRefExoticComponent<import("../../..").BadgeProps & import("react").RefAttributes<HTMLDivElement>>;
6
7
  };
7
8
  export default Item;
@@ -3,6 +3,7 @@ import { useSideBarContext } from "../../SideBar.context.js";
3
3
  import Icon from "./components/Icon/Icon.js";
4
4
  import Text from "./components/Text/Text.js";
5
5
  import Button from "./components/Button/Button.js";
6
+ import Badge from "./components/Badge/Badge.js";
6
7
  import { SideBarItem, TooltipContent } from "./Item.style.js";
7
8
  import { jsx } from "react/jsx-runtime";
8
9
  import { useRef } from "react";
@@ -38,7 +39,8 @@ var Item = Object.assign(({ tooltipProps, isActive = false, onKeyDown, ...restPr
38
39
  }, {
39
40
  Icon,
40
41
  Text,
41
- Button
42
+ Button,
43
+ Badge
42
44
  });
43
45
  //#endregion
44
46
  export { Item as default };
@@ -17,13 +17,15 @@ var SideBarItem = styled_components.default.li.withConfig({
17
17
  ";}",
18
18
  ";& > svg{transition:inherit;}"
19
19
  ], () => (0, _redislabsdev_redis_ui_styles.useTheme)().core.focus.size, () => (0, _redislabsdev_redis_ui_styles.useTheme)().core.focus.color, () => (0, _redislabsdev_redis_ui_styles.useTheme)().core.focus.size, () => {
20
- return require_SideBar_utils.useStateStyle(({ item: theme }) => {
20
+ return require_SideBar_utils.useStateStyle(({ item: theme }, state) => {
21
21
  const { states } = theme;
22
22
  return styled_components.css`
23
23
  margin: ${theme.margin};
24
- :has(> button) {
25
- margin-inline-end: ${theme.itemWithButtonOffset};
26
- }
24
+ ${state === "expanded" && styled_components.css`
25
+ :has(> button) {
26
+ margin-inline-end: ${theme.itemWithButtonOffset};
27
+ }
28
+ `}
27
29
  height: ${theme.height};
28
30
  padding: ${theme.padding};
29
31
  border-radius: ${theme.borderRadius};
@@ -51,6 +53,17 @@ var SideBarItem = styled_components.default.li.withConfig({
51
53
  fallbackTokens: states.normal
52
54
  })}
53
55
  }
56
+
57
+ &[data-state='active']::before {
58
+ content: '';
59
+ position: absolute;
60
+ left: ${theme.activeIndicator.left};
61
+ top: ${theme.activeIndicator.top};
62
+ bottom: ${theme.activeIndicator.bottom};
63
+ width: ${theme.activeIndicator.width};
64
+ background-color: ${theme.activeIndicator.bgColor};
65
+ border-radius: ${theme.activeIndicator.borderRadius};
66
+ }
54
67
  `;
55
68
  });
56
69
  });
@@ -15,13 +15,15 @@ var SideBarItem = _styled.li.withConfig({
15
15
  ";}",
16
16
  ";& > svg{transition:inherit;}"
17
17
  ], () => useTheme().core.focus.size, () => useTheme().core.focus.color, () => useTheme().core.focus.size, () => {
18
- return useStateStyle(({ item: theme }) => {
18
+ return useStateStyle(({ item: theme }, state) => {
19
19
  const { states } = theme;
20
20
  return css`
21
21
  margin: ${theme.margin};
22
- :has(> button) {
23
- margin-inline-end: ${theme.itemWithButtonOffset};
24
- }
22
+ ${state === "expanded" && css`
23
+ :has(> button) {
24
+ margin-inline-end: ${theme.itemWithButtonOffset};
25
+ }
26
+ `}
25
27
  height: ${theme.height};
26
28
  padding: ${theme.padding};
27
29
  border-radius: ${theme.borderRadius};
@@ -49,6 +51,17 @@ var SideBarItem = _styled.li.withConfig({
49
51
  fallbackTokens: states.normal
50
52
  })}
51
53
  }
54
+
55
+ &[data-state='active']::before {
56
+ content: '';
57
+ position: absolute;
58
+ left: ${theme.activeIndicator.left};
59
+ top: ${theme.activeIndicator.top};
60
+ bottom: ${theme.activeIndicator.bottom};
61
+ width: ${theme.activeIndicator.width};
62
+ background-color: ${theme.activeIndicator.bgColor};
63
+ border-radius: ${theme.activeIndicator.borderRadius};
64
+ }
52
65
  `;
53
66
  });
54
67
  });
@@ -0,0 +1,18 @@
1
+ const require_runtime = require("../../../../../_virtual/_rolldown/runtime.cjs");
2
+ const require_SideBar_context = require("../../../../SideBar.context.cjs");
3
+ const require_Badge_style = require("./Badge.style.cjs");
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ let react = require("react");
6
+ react = require_runtime.__toESM(react, 1);
7
+ //#region src/SideBar/components/Item/components/Badge/Badge.tsx
8
+ var Badge = react.default.forwardRef((props, ref) => {
9
+ const { isExpanded, transitionEnd } = require_SideBar_context.useSideBarContext();
10
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Badge_style.Badge, {
11
+ ref,
12
+ $isExpanded: isExpanded,
13
+ $transitionEnd: transitionEnd,
14
+ ...props
15
+ });
16
+ });
17
+ //#endregion
18
+ exports.default = Badge;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import { BadgeProps } from '../../../../../Badge/Badge.types';
3
+ declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLDivElement>>;
4
+ export default Badge;
@@ -0,0 +1,16 @@
1
+ import { useSideBarContext } from "../../../../SideBar.context.js";
2
+ import { Badge as Badge$1 } from "./Badge.style.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import React from "react";
5
+ //#region src/SideBar/components/Item/components/Badge/Badge.tsx
6
+ var Badge = React.forwardRef((props, ref) => {
7
+ const { isExpanded, transitionEnd } = useSideBarContext();
8
+ return /* @__PURE__ */ jsx(Badge$1, {
9
+ ref,
10
+ $isExpanded: isExpanded,
11
+ $transitionEnd: transitionEnd,
12
+ ...props
13
+ });
14
+ });
15
+ //#endregion
16
+ export { Badge as default };
@@ -0,0 +1,11 @@
1
+ const require_runtime = require("../../../../../_virtual/_rolldown/runtime.cjs");
2
+ const require_Badge = require("../../../../../Badge/Badge.cjs");
3
+ let styled_components = require("styled-components");
4
+ styled_components = require_runtime.__toESM(styled_components, 1);
5
+ //#region src/SideBar/components/Item/components/Badge/Badge.style.ts
6
+ var Badge = (0, styled_components.default)(require_Badge.default).withConfig({
7
+ displayName: "Badgestyle__Badge",
8
+ componentId: "RedisUI__sc-am1mdr-0"
9
+ })(["margin-inline-start:auto;transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:", ";"], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0");
10
+ //#endregion
11
+ exports.Badge = Badge;
@@ -0,0 +1,4 @@
1
+ export declare const Badge: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../../../../..").BadgeProps & import("react").RefAttributes<HTMLDivElement>>, any, {
2
+ $isExpanded: boolean;
3
+ $transitionEnd: boolean;
4
+ }, never>;
@@ -0,0 +1,9 @@
1
+ import Badge$1 from "../../../../../Badge/Badge.js";
2
+ import _styled from "styled-components";
3
+ //#region src/SideBar/components/Item/components/Badge/Badge.style.ts
4
+ var Badge = _styled(Badge$1).withConfig({
5
+ displayName: "Badgestyle__Badge",
6
+ componentId: "RedisUI__sc-am1mdr-0"
7
+ })(["margin-inline-start:auto;transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:", ";"], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0");
8
+ //#endregion
9
+ export { Badge };
@@ -6,12 +6,19 @@ let react = require("react");
6
6
  react = require_runtime.__toESM(react, 1);
7
7
  //#region src/SideBar/components/Item/components/Button/Button.tsx
8
8
  var Button = react.default.forwardRef(({ size = "M", ...props }, ref) => {
9
- const { isExpanded } = require_SideBar_context.useSideBarContext();
10
- return isExpanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Button_style.SideBarItemButton, {
9
+ const { isExpanded, transitionEnd } = require_SideBar_context.useSideBarContext();
10
+ const isHidden = !isExpanded || !transitionEnd;
11
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Button_style.SideBarItemButton, {
11
12
  size,
12
13
  ref,
13
- ...props
14
- }) : null;
14
+ $isExpanded: isExpanded,
15
+ $transitionEnd: transitionEnd,
16
+ ...props,
17
+ ...isHidden && {
18
+ tabIndex: -1,
19
+ "aria-hidden": true
20
+ }
21
+ });
15
22
  });
16
23
  //#endregion
17
24
  exports.default = Button;
@@ -4,12 +4,19 @@ import { jsx } from "react/jsx-runtime";
4
4
  import React from "react";
5
5
  //#region src/SideBar/components/Item/components/Button/Button.tsx
6
6
  var Button = React.forwardRef(({ size = "M", ...props }, ref) => {
7
- const { isExpanded } = useSideBarContext();
8
- return isExpanded ? /* @__PURE__ */ jsx(SideBarItemButton, {
7
+ const { isExpanded, transitionEnd } = useSideBarContext();
8
+ const isHidden = !isExpanded || !transitionEnd;
9
+ return /* @__PURE__ */ jsx(SideBarItemButton, {
9
10
  size,
10
11
  ref,
11
- ...props
12
- }) : null;
12
+ $isExpanded: isExpanded,
13
+ $transitionEnd: transitionEnd,
14
+ ...props,
15
+ ...isHidden && {
16
+ tabIndex: -1,
17
+ "aria-hidden": true
18
+ }
19
+ });
13
20
  });
14
21
  //#endregion
15
22
  export { Button as default };
@@ -7,7 +7,12 @@ styled_components = require_runtime.__toESM(styled_components, 1);
7
7
  var SideBarItemButton = (0, styled_components.default)(require_ActionIconButton.default).withConfig({
8
8
  displayName: "Buttonstyle__SideBarItemButton",
9
9
  componentId: "RedisUI__sc-13x3wha-0"
10
- })(["position:absolute;padding:0;right:0;transform:translateX(50%);", ""], () => require_SideBar_utils.useStateStyle((theme) => styled_components.css`
10
+ })([
11
+ "position:absolute;padding:0;right:0;transform:translateX(50%);transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:",
12
+ ";pointer-events:",
13
+ ";",
14
+ ""
15
+ ], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0", ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "auto" : "none", () => require_SideBar_utils.useStateStyle((theme) => styled_components.css`
11
16
  background-color: ${theme.item.button.bgColor};
12
17
  border-color: ${theme.item.button.borderColor};
13
18
  border-width: ${theme.item.button.borderSize};
@@ -1 +1,4 @@
1
- export declare const SideBarItemButton: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../../../../..").ActionIconButtonProps & import("react").RefAttributes<HTMLButtonElement>>, any, {}, never>;
1
+ export declare const SideBarItemButton: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../../../../..").ActionIconButtonProps & import("react").RefAttributes<HTMLButtonElement>>, any, {
2
+ $isExpanded: boolean;
3
+ $transitionEnd: boolean;
4
+ }, never>;
@@ -5,7 +5,12 @@ import _styled, { css } from "styled-components";
5
5
  var SideBarItemButton = _styled(ActionIconButton).withConfig({
6
6
  displayName: "Buttonstyle__SideBarItemButton",
7
7
  componentId: "RedisUI__sc-13x3wha-0"
8
- })(["position:absolute;padding:0;right:0;transform:translateX(50%);", ""], () => useStateStyle((theme) => css`
8
+ })([
9
+ "position:absolute;padding:0;right:0;transform:translateX(50%);transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:",
10
+ ";pointer-events:",
11
+ ";",
12
+ ""
13
+ ], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0", ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "auto" : "none", () => useStateStyle((theme) => css`
9
14
  background-color: ${theme.item.button.bgColor};
10
15
  border-color: ${theme.item.button.borderColor};
11
16
  border-width: ${theme.item.button.borderSize};
@@ -1,12 +1,18 @@
1
1
  require("../../../../../_virtual/_rolldown/runtime.cjs");
2
+ const require_SideBar_context = require("../../../../SideBar.context.cjs");
2
3
  const require_Text_style = require("./Text.style.cjs");
3
4
  let react_jsx_runtime = require("react/jsx-runtime");
4
5
  //#region src/SideBar/components/Item/components/Text/Text.tsx
5
- var Text = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Text_style.SideBarItemText, {
6
- ellipsis: true,
7
- tooltipOnEllipsis: true,
8
- component: "span",
9
- ...props
10
- });
6
+ var Text = (props) => {
7
+ const { isExpanded, transitionEnd } = require_SideBar_context.useSideBarContext();
8
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Text_style.SideBarItemText, {
9
+ ellipsis: true,
10
+ tooltipOnEllipsis: true,
11
+ component: "span",
12
+ $isExpanded: isExpanded,
13
+ $transitionEnd: transitionEnd,
14
+ ...props
15
+ });
16
+ };
11
17
  //#endregion
12
18
  exports.default = Text;
@@ -1,11 +1,17 @@
1
+ import { useSideBarContext } from "../../../../SideBar.context.js";
1
2
  import { SideBarItemText } from "./Text.style.js";
2
3
  import { jsx } from "react/jsx-runtime";
3
4
  //#region src/SideBar/components/Item/components/Text/Text.tsx
4
- var Text = (props) => /* @__PURE__ */ jsx(SideBarItemText, {
5
- ellipsis: true,
6
- tooltipOnEllipsis: true,
7
- component: "span",
8
- ...props
9
- });
5
+ var Text = (props) => {
6
+ const { isExpanded, transitionEnd } = useSideBarContext();
7
+ return /* @__PURE__ */ jsx(SideBarItemText, {
8
+ ellipsis: true,
9
+ tooltipOnEllipsis: true,
10
+ component: "span",
11
+ $isExpanded: isExpanded,
12
+ $transitionEnd: transitionEnd,
13
+ ...props
14
+ });
15
+ };
10
16
  //#endregion
11
17
  export { Text as default };
@@ -1,15 +1,11 @@
1
1
  const require_runtime = require("../../../../../_virtual/_rolldown/runtime.cjs");
2
2
  const require_Typography = require("../../../../../Typography/Typography.cjs");
3
- const require_SideBar_context = require("../../../../SideBar.context.cjs");
4
3
  let styled_components = require("styled-components");
5
4
  styled_components = require_runtime.__toESM(styled_components, 1);
6
5
  //#region src/SideBar/components/Item/components/Text/Text.style.ts
7
6
  var SideBarItemText = (0, styled_components.default)(require_Typography.default.Body).withConfig({
8
7
  displayName: "Textstyle__SideBarItemText",
9
8
  componentId: "RedisUI__sc-17tjfvd-0"
10
- })(["transition:width 0.6s,opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:", ";"], () => {
11
- const { isExpanded, transitionEnd } = require_SideBar_context.useSideBarContext();
12
- return isExpanded && transitionEnd ? "1" : "0";
13
- });
9
+ })(["transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:", ";"], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0");
14
10
  //#endregion
15
11
  exports.SideBarItemText = SideBarItemText;
@@ -1 +1,4 @@
1
- export declare const SideBarItemText: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../../../../../Typography").TypographyBodyProps & import("react").RefAttributes<HTMLElement>>, any, {}, never>;
1
+ export declare const SideBarItemText: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../../../../../Typography").TypographyBodyProps & import("react").RefAttributes<HTMLElement>>, any, {
2
+ $isExpanded: boolean;
3
+ $transitionEnd: boolean;
4
+ }, never>;
@@ -1,13 +1,9 @@
1
1
  import Typography from "../../../../../Typography/Typography.js";
2
- import { useSideBarContext } from "../../../../SideBar.context.js";
3
2
  import _styled from "styled-components";
4
3
  //#region src/SideBar/components/Item/components/Text/Text.style.ts
5
4
  var SideBarItemText = _styled(Typography.Body).withConfig({
6
5
  displayName: "Textstyle__SideBarItemText",
7
6
  componentId: "RedisUI__sc-17tjfvd-0"
8
- })(["transition:width 0.6s,opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:", ";"], () => {
9
- const { isExpanded, transitionEnd } = useSideBarContext();
10
- return isExpanded && transitionEnd ? "1" : "0";
11
- });
7
+ })(["transition:opacity 0.4s;@media (prefers-reduced-motion:reduce){transition:none;}opacity:", ";"], ({ $isExpanded, $transitionEnd }) => $isExpanded && $transitionEnd ? "1" : "0");
12
8
  //#endregion
13
9
  export { SideBarItemText };
@@ -6,6 +6,6 @@ styled_components = require_runtime.__toESM(styled_components, 1);
6
6
  var ScrollContainer = (0, styled_components.default)(require_FlexGroup.FlexGroup).withConfig({
7
7
  displayName: "ScrollContainerstyle__ScrollContainer",
8
8
  componentId: "RedisUI__sc-15iez38-0"
9
- })(["overflow-y:auto;"]);
9
+ })(["overflow-y:auto;overflow-x:hidden;scrollbar-gutter:stable;"]);
10
10
  //#endregion
11
11
  exports.ScrollContainer = ScrollContainer;
@@ -4,6 +4,6 @@ import _styled from "styled-components";
4
4
  var ScrollContainer = _styled(FlexGroup).withConfig({
5
5
  displayName: "ScrollContainerstyle__ScrollContainer",
6
6
  componentId: "RedisUI__sc-15iez38-0"
7
- })(["overflow-y:auto;"]);
7
+ })(["overflow-y:auto;overflow-x:hidden;scrollbar-gutter:stable;"]);
8
8
  //#endregion
9
9
  export { ScrollContainer };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@redis-ui/components",
3
3
  "license": "UNLICENSED",
4
- "version": "47.0.1",
4
+ "version": "47.2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "repository": "git@github.com:redislabsdev/redis-ui.git",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@redis-ui/icons": "^8.0.0",
33
- "@redis-ui/styles": "^16.0.0",
33
+ "@redis-ui/styles": "^16.3.0",
34
34
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
35
35
  "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
36
36
  "styled-components": "^5.0.0"
@@ -1,6 +1,6 @@
1
1
  # SideBar
2
2
 
3
- Collapsible sidebar navigation with a header toggle, grouped items, scrollable middle content, and a footer area. The component is designed as a compound API so the header, items, splitters, and footer pieces can be composed as needed.
3
+ Collapsible sidebar navigation with a header toggle, grouped items, scrollable middle content, and a footer area. The component is designed as a compound API so the header, items, splitters, group titles, and footer pieces can be composed as needed.
4
4
 
5
5
  ## Import
6
6
 
@@ -13,6 +13,7 @@ import { SideBar } from '@redis-ui/components';
13
13
  | Prop | Type | Default | Description |
14
14
  |------|------|---------|-------------|
15
15
  | isExpanded | `boolean` | *required* | Controls whether the sidebar is expanded or collapsed |
16
+ | expandedWidth | `string` | design-system default | Overrides the sidebar width when expanded |
16
17
 
17
18
  The component also accepts all `FlexGroupProps` except `direction`, which is fixed to a vertical sidebar layout.
18
19
 
@@ -28,7 +29,10 @@ The component also accepts all `FlexGroupProps` except `direction`, which is fix
28
29
  - `SideBar.Item` - Navigation item with tooltip support when collapsed.
29
30
  - `SideBar.Item.Icon` - Icon slot for a sidebar item.
30
31
  - `SideBar.Item.Text` - Text slot for a sidebar item.
31
- - `SideBar.Item.Button` - Compact action button that is shown only when the sidebar is expanded.
32
+ - `SideBar.Item.Button` - Compact action button rendered inside a sidebar item.
33
+ - `SideBar.Item.Badge` - Badge slot rendered to the right of `Item.Text` (e.g. `NEW`, `BETA`).
34
+ - `SideBar.Group` - Wrapper around a section's `Group.Title` and items. Use one `SideBar.Group` per logical section.
35
+ - `SideBar.Group.Title` - Section label rendered above a group of items.
32
36
  - `SideBar.Footer` - Footer wrapper for metadata, links, and text.
33
37
  - `SideBar.Footer.MetaData` - Footer metadata container.
34
38
  - `SideBar.Footer.Link` - Footer link rendered as body text.
@@ -52,11 +56,11 @@ The logo also accepts standard `HTMLAttributes<HTMLSpanElement>` except `childre
52
56
 
53
57
  ### SideBar.ItemsContainer Props
54
58
 
55
- This component inherits `FlexGroupProps` except `direction`. It renders a column list container with `gap="0"`, `flex="none"`, and `selfAlign="stretch"`.
59
+ This component inherits `FlexGroupProps` except `direction`. Use it to render a vertical list of sidebar items.
56
60
 
57
61
  ### SideBar.ScrollContainer Props
58
62
 
59
- This component inherits `FlexGroupProps` except `direction`. It renders a flexible column container with `gap="0"`, `flex="1"`, and `selfAlign="stretch"`.
63
+ This component inherits `FlexGroupProps` except `direction`. Use it for sidebar content that should scroll when vertical space is constrained.
60
64
 
61
65
  ### SideBar.Divider Props
62
66
 
@@ -73,7 +77,7 @@ The divider also accepts standard `HTMLAttributes<HTMLDivElement>` except `child
73
77
  | Prop | Type | Default | Description |
74
78
  |------|------|---------|-------------|
75
79
  | tooltipProps | `SideBarTooltipProps` | *required* | Tooltip configuration used when the sidebar is collapsed |
76
- | isActive | `boolean` | `false` | Marks the item as the active route/item |
80
+ | isActive | `boolean` | `false` | Marks the item as the active route/item and applies the design-system active visual treatment |
77
81
 
78
82
  The item also accepts standard `HTMLAttributes<HTMLLIElement>`.
79
83
  The tooltip text is used as the collapsed label and tooltip placement defaults to `right`.
@@ -86,11 +90,27 @@ The tooltip text is used as the collapsed label and tooltip placement defaults t
86
90
 
87
91
  ### SideBar.Item.Text Props
88
92
 
89
- This slot inherits `TypographyBodyProps`. It renders a `Typography.Body` element with `component="span"`, `ellipsis`, and `tooltipOnEllipsis` enabled.
93
+ This slot inherits `TypographyBodyProps`. Use it for the sidebar item text label.
90
94
 
91
95
  ### SideBar.Item.Button Props
92
96
 
93
- This slot inherits all `ActionIconButtonProps`, defaults `size` to `M`, and renders only while the sidebar is expanded.
97
+ This slot inherits all `ActionIconButtonProps` and defaults `size` to `M`. It is available when the sidebar is expanded and hidden while collapsed.
98
+
99
+ ### SideBar.Item.Badge Props
100
+
101
+ This slot inherits all `BadgeProps` from the base `Badge` component. It is shown next to item text when the sidebar is expanded and hidden while collapsed.
102
+
103
+ ### SideBar.Group Props
104
+
105
+ This wrapper accepts standard `HTMLAttributes<HTMLDivElement>`. Place a `SideBar.Group.Title` and the section's items inside.
106
+
107
+ ### SideBar.Group.Title Props
108
+
109
+ | Prop | Type | Default | Description |
110
+ |------|------|---------|-------------|
111
+ | children | `React.ReactNode` | *required* | Title text shown above the group of items |
112
+
113
+ The group title also accepts standard `HTMLAttributes<HTMLDivElement>` except `children`. It is shown when the sidebar is expanded and hidden while collapsed.
94
114
 
95
115
  ### SideBar.Button Props
96
116
 
@@ -129,7 +149,7 @@ The link also accepts standard `AnchorHTMLAttributes<HTMLAnchorElement>` except
129
149
  |------|------|---------|-------------|
130
150
  | children | `React.ReactNode` | *required* | Footer text content |
131
151
 
132
- This slot inherits `TypographyBodyProps` except `children` and renders a small body-text footer line.
152
+ This slot inherits `TypographyBodyProps` except `children` and renders footer text.
133
153
 
134
154
  ## Examples
135
155
 
@@ -249,6 +269,66 @@ const [activeLink, setActiveLink] = useState(items.top[0].content);
249
269
  </SideBar>
250
270
  ```
251
271
 
272
+ ### Groups
273
+
274
+ > Sidebar items can be split into groups, each with an optional title label. Items inside a group may also render an optional `SideBar.Item.Badge` (e.g. `NEW`, `BETA`) to the right of the text.
275
+
276
+ ```tsx
277
+ import { SideBar } from '@redis-ui/components';
278
+ import { PlusIcon } from '@redis-ui/icons';
279
+ import { useState } from 'react';
280
+ import { RedisIcon } from '@redis-ui/icons/multicolor';
281
+ import { groups } from './SideBar.data';
282
+
283
+ const [expanded, setExpanded] = useState(true);
284
+ const [activeLink, setActiveLink] = useState(groups[0].items[0].content);
285
+
286
+ <SideBar
287
+ isExpanded={expanded}
288
+ style={{ maxHeight: '55rem', height: 'calc(100vh - 2rem)' }}
289
+ expandedWidth="35rem"
290
+ >
291
+ <SideBar.Header onToggle={() => setExpanded(!expanded)}>
292
+ <SideBar.SideBarLogo logoIcon={RedisIcon} />
293
+ </SideBar.Header>
294
+ <SideBar.ScrollContainer>
295
+ {groups.map((group, groupIdx) => (
296
+ <SideBar.Group key={group.title ?? `group-${groupIdx}`}>
297
+ {group.title && <SideBar.Group.Title>{group.title}</SideBar.Group.Title>}
298
+ <SideBar.ItemsContainer>
299
+ {group.items.map((item) => (
300
+ <SideBar.Item
301
+ isActive={item.content === activeLink}
302
+ onClick={() => setActiveLink(item.content)}
303
+ key={item.content}
304
+ tooltipProps={{ text: item.content, placement: 'right' }}
305
+ >
306
+ <SideBar.Item.Icon icon={item.icon} />
307
+ <SideBar.Item.Text>{item.content}</SideBar.Item.Text>
308
+ {'badge' in item && item.badge && (
309
+ <SideBar.Item.Badge label={item.badge.label} variant={item.badge.variant} />
310
+ )}
311
+ {'hasButton' in item && item.hasButton && (
312
+ <SideBar.Item.Button
313
+ icon={PlusIcon}
314
+ variant="primary"
315
+ onClick={(e) => e.stopPropagation()}
316
+ title={`New ${item.content}`}
317
+ />
318
+ )}
319
+ </SideBar.Item>
320
+ ))}
321
+ </SideBar.ItemsContainer>
322
+ </SideBar.Group>
323
+ ))}
324
+ </SideBar.ScrollContainer>
325
+ <SideBar.Footer>
326
+ <SideBar.Divider fullWidth />
327
+ <SideBar.Footer.MetaData>© 2026 Redis</SideBar.Footer.MetaData>
328
+ </SideBar.Footer>
329
+ </SideBar>
330
+ ```
331
+
252
332
  ### HeaderAndFooter
253
333
 
254
334
  > `Header` includes toggle button and. Set `onToggle` handler to switch expanded state.
@@ -458,11 +538,15 @@ const [expanded, setExpanded] = useState(true);
458
538
  ## Notes
459
539
 
460
540
  - `SideBar` is a collapsible navigation shell with a fixed header/footer layout and grouped content in the middle.
541
+ - Hosts can override the expanded width by passing the `expandedWidth` prop.
461
542
  - `SideBar.Header` needs an `onToggle` handler and should usually render `SideBar.SideBarLogo` inside it.
462
543
  - `SideBar.Footer` is typically used with `Footer.MetaData`; that metadata area is hidden when the sidebar is collapsed.
463
544
  - `SideBar.ScrollContainer` is intended for the middle content when vertical space is constrained, and the docs recommend using only one per sidebar.
464
545
  - `SideBar.Split` can be used either directly under `SideBar` or under `SideBar.ScrollContainer`, but the two patterns should not be mixed.
465
546
  - `SideBar.Divider` supports `noMargin`, `fullWidth`, and `fullWidthWhenExpanded` for layout tuning.
466
- - `SideBar.Item` wraps collapsed items in a tooltip and exposes `Item.Icon`, `Item.Text`, and `Item.Button` for composition.
467
- - `SideBar.Item.Button` only renders while the sidebar is expanded and defaults its size to `M`.
547
+ - `SideBar.Item` wraps collapsed items in a tooltip and exposes `Item.Icon`, `Item.Text`, `Item.Button`, and `Item.Badge` for composition.
548
+ - `SideBar.Item` supports the `isActive` prop for marking the current route or selected item.
549
+ - `SideBar.Item.Button` defaults its size to `M`.
468
550
  - `SideBar.Button` is the root collapsible action button, and it defaults to `PlusIcon` when no collapsed icon is provided.
551
+ - `SideBar.Group` wraps a section's `Group.Title` (optional) and items so the title and the items stay together as one logical unit.
552
+ - `SideBar.Group.Title` labels a group of items. Pair `SideBar.Item.Badge` with `Item.Text` if you need to mark individual items as `NEW`, `BETA`, etc.