shivanya-sdk 0.1.1 → 0.1.2

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 (64) hide show
  1. package/package.json +1 -1
  2. package/packages/shell/package.json +2 -2
  3. package/packages/shell/scripts/copy-assets.mjs +15 -5
  4. package/packages/shell/src/components/DrawerHeader.tsx +34 -9
  5. package/packages/shell/src/components/ShellBrand.tsx +12 -6
  6. package/packages/shell/src/components/ShellFooter.tsx +19 -6
  7. package/packages/shell/src/components/ShellHeader.tsx +21 -38
  8. package/packages/shell/src/components/ShellMobileNav.tsx +118 -29
  9. package/packages/shell/src/components/ShellRoot.tsx +10 -5
  10. package/packages/shell/src/components/ShellSidebar.tsx +102 -41
  11. package/packages/shell/src/components/SidebarFooter.tsx +30 -10
  12. package/packages/shell/src/hooks/useShell.ts +6 -4
  13. package/packages/shell/src/index.ts +1 -1
  14. package/packages/shell/src/layouts/AppShell.tsx +4 -2
  15. package/packages/shell/src/layouts/BlankShell.tsx +15 -6
  16. package/packages/shell/src/layouts/CenteredShell.tsx +26 -7
  17. package/packages/shell/src/layouts/DashboardShell.tsx +37 -38
  18. package/packages/shell/src/layouts/PageContainer.tsx +28 -9
  19. package/packages/shell/src/layouts/PageHeader.tsx +41 -13
  20. package/packages/shell/src/layouts/WebsiteShell.tsx +44 -11
  21. package/packages/shell/src/styles/blank-shell.css +6 -0
  22. package/packages/shell/src/styles/centered-shell.css +26 -0
  23. package/packages/shell/src/styles/dashboard-shell.css +108 -0
  24. package/packages/shell/src/styles/index.ts +14 -1
  25. package/packages/shell/src/styles/page-container.css +41 -0
  26. package/packages/shell/src/styles/page-header.css +71 -0
  27. package/packages/shell/src/styles/shell-brand.css +42 -0
  28. package/packages/shell/src/styles/shell-drawer-header.css +24 -0
  29. package/packages/shell/src/styles/shell-footer.css +65 -0
  30. package/packages/shell/src/styles/shell-header.css +68 -0
  31. package/packages/shell/src/styles/shell-main.css +17 -0
  32. package/packages/shell/src/styles/shell-mobile-nav.css +148 -0
  33. package/packages/shell/src/styles/shell-root.css +9 -0
  34. package/packages/shell/src/styles/shell-sidebar-footer.css +57 -0
  35. package/packages/shell/src/styles/shell-sidebar.css +146 -0
  36. package/packages/shell/src/styles/website-shell.css +51 -0
  37. package/packages/shell/tsconfig.json +2 -2
  38. package/playground/public/logo.png +0 -0
  39. package/playground/src/demos/shell/Components/DrawerHeaderDemo.tsx +92 -4
  40. package/playground/src/demos/shell/Components/PageContainerDemo.tsx +146 -4
  41. package/playground/src/demos/shell/Components/PageHeaderDemo.tsx +113 -5
  42. package/playground/src/demos/shell/Components/ShellBrandDemo.tsx +115 -6
  43. package/playground/src/demos/shell/Components/ShellFooterDemo.tsx +101 -4
  44. package/playground/src/demos/shell/Components/ShellHeaderDemo.tsx +131 -26
  45. package/playground/src/demos/shell/Components/ShellMainDemo.tsx +100 -5
  46. package/playground/src/demos/shell/Components/ShellMobileNavDemo.tsx +229 -6
  47. package/playground/src/demos/shell/Components/ShellRootDemo.tsx +64 -1
  48. package/playground/src/demos/shell/Components/ShellSidebarDemo.tsx +381 -8
  49. package/playground/src/demos/shell/Components/SidebarFooterDemo.tsx +107 -4
  50. package/playground/src/demos/shell/Layouts/AppShellDemo.tsx +123 -8
  51. package/playground/src/demos/shell/Layouts/BlankShellDemo.tsx +63 -6
  52. package/playground/src/demos/shell/Layouts/CenteredShellDemo.tsx +73 -10
  53. package/playground/src/demos/shell/Layouts/DashboardShellDemo.tsx +102 -15
  54. package/playground/src/demos/shell/Layouts/WebsiteShellDemo.tsx +143 -8
  55. package/playground/src/demos/shell/_demo-utils.tsx +101 -11
  56. package/playground/src/demos/shell/previews/AppShellPreview.tsx +29 -13
  57. package/playground/src/demos/shell/previews/BlankShellPreview.tsx +5 -2
  58. package/playground/src/demos/shell/previews/CenteredShellPreview.tsx +16 -1
  59. package/playground/src/demos/shell/previews/DashboardShellPreview.tsx +25 -6
  60. package/playground/src/demos/shell/previews/WebsiteShellPreview.tsx +92 -10
  61. package/playground/src/demos/shell/shell-demo.css +211 -0
  62. package/playground/src/pages/CategoryPage.tsx +0 -2
  63. package/pnpm-workspace.yaml +1 -1
  64. package/packages/shell/src/styles/shell.css +0 -534
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shivanya-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Shivanya SDK monorepo",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shivanya-shell",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "Reusable React shell, layout, and application structure components for Shivanya applications",
6
6
  "main": "dist/index.js",
@@ -19,7 +19,7 @@
19
19
  "build": "tsc && node scripts/copy-assets.mjs"
20
20
  },
21
21
  "dependencies": {
22
- "shivanya-ui": "^1.0.5"
22
+ "shivanya-ui": "^1.0.6"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": "^18.0.0 || ^19.0.0",
@@ -5,10 +5,20 @@ import { fileURLToPath } from "node:url";
5
5
  const currentFile = fileURLToPath(import.meta.url);
6
6
  const root = path.resolve(path.dirname(currentFile), "..");
7
7
 
8
- const source = path.join(root, "src", "styles", "shell.css");
9
- const target = path.join(root, "dist", "styles", "shell.css");
8
+ const source = path.join(root, "src", "styles");
9
+ const target = path.join(root, "dist", "styles");
10
10
 
11
- fs.mkdirSync(path.dirname(target), { recursive: true });
12
- fs.copyFileSync(source, target);
11
+ fs.mkdirSync(target, { recursive: true });
13
12
 
14
- console.log("Shivanya Shell CSS copied.");
13
+ for (const file of fs.readdirSync(source)) {
14
+ if (!file.endsWith(".css")) {
15
+ continue;
16
+ }
17
+
18
+ fs.copyFileSync(
19
+ path.join(source, file),
20
+ path.join(target, file),
21
+ );
22
+ }
23
+
24
+ console.log("Shivanya Shell CSS and assets copied.");
@@ -1,19 +1,44 @@
1
+ import {
2
+ CloseIcon,
3
+ IconButton,
4
+ } from "shivanya-ui";
5
+
1
6
  import type { ShellBranding } from "../types/shell.js";
2
7
  import { ShellBrand } from "./ShellBrand.js";
3
8
 
9
+ export interface DrawerHeaderProps {
10
+ branding?: ShellBranding;
11
+ onClose?: () => void;
12
+ }
13
+
4
14
  export function DrawerHeader({
5
15
  branding,
6
16
  onClose,
7
- }: {
8
- branding?: ShellBranding;
9
- onClose?: () => void;
10
- }) {
17
+ }: DrawerHeaderProps) {
11
18
  return (
12
19
  <header className="shivanya-shell-drawer-header">
13
- {branding && <ShellBrand branding={{ ...branding, href: undefined }} />}
14
- <button type="button" onClick={onClose} aria-label="Close menu">
15
- ×
16
- </button>
20
+ {branding && (
21
+ <ShellBrand
22
+ branding={{
23
+ ...branding,
24
+ href: undefined,
25
+ }}
26
+ compact={false}
27
+ />
28
+ )}
29
+
30
+ <IconButton
31
+ size="sm"
32
+ variant="ghost"
33
+ rounded
34
+ iconRotateOnHover
35
+ iconHoverColor="var(--shivanya-color-primary)"
36
+ aria-label="Close menu"
37
+ title="Close menu"
38
+ onClick={onClose}
39
+ >
40
+ <CloseIcon size="sm" />
41
+ </IconButton>
17
42
  </header>
18
43
  );
19
- }
44
+ }
@@ -1,12 +1,14 @@
1
1
  import type { ShellBranding } from "../types/shell.js";
2
2
 
3
+ interface ShellBrandProps {
4
+ branding: ShellBranding;
5
+ compact?: boolean;
6
+ }
7
+
3
8
  export function ShellBrand({
4
9
  branding,
5
10
  compact = false,
6
- }: {
7
- branding: ShellBranding;
8
- compact?: boolean;
9
- }) {
11
+ }: ShellBrandProps) {
10
12
  const content = (
11
13
  <span className="shivanya-shell-brand-content">
12
14
  {branding.src ? (
@@ -16,17 +18,21 @@ export function ShellBrand({
16
18
  className="shivanya-shell-brand-image"
17
19
  />
18
20
  ) : null}
21
+
19
22
  <span className="shivanya-shell-brand-text">
20
23
  {branding.name && <strong>{branding.name}</strong>}
21
24
  {!compact && branding.subtitle && <small>{branding.subtitle}</small>}
22
25
  </span>
23
26
  </span>
24
27
  );
25
- if (branding.href)
28
+
29
+ if (branding.href) {
26
30
  return (
27
31
  <a className="shivanya-shell-brand" href={branding.href}>
28
32
  {content}
29
33
  </a>
30
34
  );
35
+ }
36
+
31
37
  return <span className="shivanya-shell-brand">{content}</span>;
32
- }
38
+ }
@@ -7,12 +7,25 @@ export function ShellFooter({
7
7
  className = "",
8
8
  }: ShellFooterProps) {
9
9
  return (
10
- <footer className={`shivanya-shell-footer ${className}`.trim()}>
11
- {branding && <ShellBrand branding={branding} />}
12
- {children}
13
- <span className="shivanya-shell-footer-copy">
10
+ <footer
11
+ className={[
12
+ "shivanya-shell-footer",
13
+ className,
14
+ ]
15
+ .filter(Boolean)
16
+ .join(" ")}
17
+ >
18
+ <div className="shivanya-shell-footer-brand">
19
+ {branding && <ShellBrand branding={branding} />}
20
+ </div>
21
+
22
+ <div className="shivanya-shell-footer-content">
23
+ {children}
24
+ </div>
25
+
26
+ <div className="shivanya-shell-footer-copy">
14
27
  © {new Date().getFullYear()}
15
- </span>
28
+ </div>
16
29
  </footer>
17
30
  );
18
- }
31
+ }
@@ -1,7 +1,8 @@
1
- "use client"
1
+ "use client";
2
2
 
3
3
  import type { CSSProperties } from "react";
4
4
  import type { ShellHeaderProps } from "../types/shell.js";
5
+ import { Button } from "shivanya-ui";
5
6
  import { useShell } from "../hooks/useShell.js";
6
7
  import { ShellBrand } from "./ShellBrand.js";
7
8
 
@@ -19,63 +20,45 @@ export function ShellHeader({
19
20
  }: ShellHeaderProps) {
20
21
  const shell = useShell();
21
22
 
22
- const menuAction = () => {
23
- if (
24
- typeof window !== "undefined" &&
25
- window.matchMedia("(max-width: 767px)").matches
26
- ) {
27
- shell.toggleMobile();
28
- } else {
29
- shell.toggleSidebar();
30
- }
31
- };
32
-
33
23
  return (
34
24
  <header
35
25
  className={`shivanya-shell-header shivanya-shell-header-${position} ${className}`.trim()}
36
26
  style={
37
27
  {
38
28
  "--shivanya-shell-header-height":
39
- typeof height === "number"
40
- ? `${height}px`
41
- : height,
29
+ typeof height === "number" ? `${height}px` : height,
42
30
  } as CSSProperties
43
31
  }
44
32
  >
45
33
  <div className="shivanya-shell-header-inner">
46
34
  <div className="shivanya-shell-header-start">
47
35
  {showMenu && (
48
- <button
49
- type="button"
50
- className="shivanya-shell-menu-button"
51
- onClick={menuAction}
52
- aria-label={menuLabel}
53
- title={menuLabel}
54
- >
55
- <span aria-hidden="true">☰</span>
56
- </button>
36
+ <div className="shivanya-shell-mobile-menu">
37
+ <Button
38
+ type="button"
39
+ variant="ghost"
40
+ size="sm"
41
+ rounded
42
+ onClick={shell.toggleMobile}
43
+ aria-label={menuLabel}
44
+ title={menuLabel}
45
+ >
46
+ ☰
47
+ </Button>
48
+ </div>
57
49
  )}
58
50
 
59
- {start}
51
+ {branding && <ShellBrand branding={branding} compact={false} />}
60
52
 
61
- {branding && (
62
- <ShellBrand
63
- branding={branding}
64
- compact={shell.sidebarCollapsed}
65
- />
66
- )}
53
+ {start}
67
54
  </div>
68
55
 
69
- <div className="shivanya-shell-header-center">
70
- {center}
71
- </div>
56
+ <div className="shivanya-shell-header-center">{center}</div>
72
57
 
73
- <div className="shivanya-shell-header-end">
74
- {end}
75
- </div>
58
+ <div className="shivanya-shell-header-end">{end}</div>
76
59
  </div>
77
60
 
78
61
  {children}
79
62
  </header>
80
63
  );
81
- }
64
+ }
@@ -1,29 +1,116 @@
1
- "use client"
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import type {
5
+ AnimationEvent,
6
+ CSSProperties,
7
+ } from "react";
2
8
 
3
- import { useEffect } from "react";
4
9
  import type { ShellMobileNavProps } from "../types/shell.js";
10
+
5
11
  import { ShellSidebar } from "./ShellSidebar.js";
6
- import { useShell } from "../hooks/useShell.js";
12
+ import { DrawerHeader } from "./DrawerHeader.js";
13
+ import { useOptionalShell } from "../hooks/useShell.js";
14
+
15
+ export function ShellMobileNav({
16
+ open: controlledOpen,
17
+ onClose: controlledOnClose,
18
+ size = 280,
19
+ className = "",
20
+ ...props
21
+ }: ShellMobileNavProps) {
22
+ const shell = useOptionalShell();
23
+
24
+ const open =
25
+ controlledOpen ?? shell?.mobileOpen ?? false;
26
+
27
+ const close =
28
+ controlledOnClose ?? shell?.closeMobile ?? (() => {});
29
+
30
+ const [mounted, setMounted] = useState(open);
7
31
 
8
- export function ShellMobileNav(props: ShellMobileNavProps) {
9
- const shell = useShell();
10
- const open = props.open ?? shell.mobileOpen;
11
- const close = props.onClose ?? shell.closeMobile;
32
+ useEffect(() => {
33
+ if (open) {
34
+ setMounted(true);
35
+ }
36
+ }, [open]);
12
37
 
13
38
  useEffect(() => {
14
- if (!open || typeof document === "undefined") return;
15
- const previous = document.body.style.overflow;
39
+ if (!mounted) {
40
+ return;
41
+ }
42
+
43
+ const previousOverflow =
44
+ document.body.style.overflow;
45
+
46
+ const previousTouchAction =
47
+ document.body.style.touchAction;
48
+
16
49
  document.body.style.overflow = "hidden";
50
+ document.body.style.touchAction = "none";
51
+
52
+ const handleKeyDown = (event: KeyboardEvent) => {
53
+ if (event.key === "Escape") {
54
+ close();
55
+ }
56
+ };
57
+
58
+ document.addEventListener(
59
+ "keydown",
60
+ handleKeyDown,
61
+ );
62
+
17
63
  return () => {
18
- document.body.style.overflow = previous;
64
+ document.body.style.overflow =
65
+ previousOverflow;
66
+
67
+ document.body.style.touchAction =
68
+ previousTouchAction;
69
+
70
+ document.removeEventListener(
71
+ "keydown",
72
+ handleKeyDown,
73
+ );
19
74
  };
20
- }, [open]);
75
+ }, [mounted, close]);
21
76
 
22
- if (!open) return null;
77
+ if (!mounted) {
78
+ return null;
79
+ }
80
+
81
+ const panelStyle = {
82
+ "--shivanya-shell-mobile-width":
83
+ typeof size === "number"
84
+ ? `${size}px`
85
+ : size,
86
+ } as CSSProperties;
87
+
88
+ const handleAnimationEnd = (
89
+ event: AnimationEvent<HTMLElement>,
90
+ ) => {
91
+ if (
92
+ event.target !== event.currentTarget ||
93
+ event.animationName !==
94
+ "shivanya-mobile-drawer-close"
95
+ ) {
96
+ return;
97
+ }
98
+
99
+ if (!open) {
100
+ setMounted(false);
101
+ }
102
+ };
23
103
 
24
104
  return (
25
105
  <div
26
- className="shivanya-shell-mobile-layer"
106
+ className={[
107
+ "shivanya-shell-mobile-layer",
108
+ open
109
+ ? "shivanya-shell-mobile-layer-open"
110
+ : "shivanya-shell-mobile-layer-closing",
111
+ ]
112
+ .filter(Boolean)
113
+ .join(" ")}
27
114
  role="dialog"
28
115
  aria-modal="true"
29
116
  aria-label="Navigation"
@@ -34,28 +121,30 @@ export function ShellMobileNav(props: ShellMobileNavProps) {
34
121
  onClick={close}
35
122
  aria-label="Close navigation"
36
123
  />
37
- <div
124
+
125
+ <aside
38
126
  className="shivanya-shell-mobile-panel"
39
- style={{
40
- width:
41
- typeof props.size === "number" ? `${props.size}px` : props.size,
42
- }}
127
+ style={panelStyle}
128
+ onAnimationEnd={handleAnimationEnd}
43
129
  >
44
- <button
45
- type="button"
46
- className="shivanya-shell-mobile-close"
47
- onClick={close}
48
- aria-label="Close navigation"
49
- >
50
- ×
51
- </button>
130
+ <DrawerHeader
131
+ branding={props.branding}
132
+ onClose={close}
133
+ />
134
+
52
135
  <ShellSidebar
53
136
  {...props}
54
137
  collapsed={false}
55
138
  variant="static"
56
- className={`shivanya-shell-mobile-sidebar ${props.className || ""}`}
139
+ branding={undefined}
140
+ className={[
141
+ "shivanya-shell-mobile-sidebar",
142
+ className,
143
+ ]
144
+ .filter(Boolean)
145
+ .join(" ")}
57
146
  />
58
- </div>
147
+ </aside>
59
148
  </div>
60
149
  );
61
- }
150
+ }
@@ -1,11 +1,16 @@
1
- import type { CSSProperties } from "react";
2
1
  import type { ShellRootProps } from "../types/shell.js";
3
- import "../styles/shell.css";
4
2
 
5
- export function ShellRoot({ children, className = "", style }: ShellRootProps) {
3
+ export function ShellRoot({
4
+ children,
5
+ className = "",
6
+ style,
7
+ }: ShellRootProps) {
6
8
  return (
7
- <div className={`shivanya-shell ${className}`.trim()} style={style}>
9
+ <div
10
+ className={`shivanya-shell ${className}`.trim()}
11
+ style={style}
12
+ >
8
13
  {children}
9
14
  </div>
10
15
  );
11
- }
16
+ }
@@ -1,6 +1,21 @@
1
+ "use client";
2
+
1
3
  import type { CSSProperties, ElementType } from "react";
2
- import type { ShellNavItem, ShellSidebarProps } from "../types/shell.js";
3
- import { getShellItemKey, isShellItemActive } from "../utils/navigation.js";
4
+ import type {
5
+ ShellNavItem,
6
+ ShellSidebarProps,
7
+ } from "../types/shell.js";
8
+
9
+ import {
10
+ Sidebar,
11
+ SidebarItem,
12
+ } from "shivanya-ui";
13
+
14
+ import {
15
+ getShellItemKey,
16
+ isShellItemActive,
17
+ } from "../utils/navigation.js";
18
+
4
19
  import { ShellBrand } from "./ShellBrand.js";
5
20
 
6
21
  export function ShellSidebar({
@@ -20,21 +35,43 @@ export function ShellSidebar({
20
35
  }: ShellSidebarProps) {
21
36
  return (
22
37
  <aside
23
- className={`shivanya-shell-sidebar shivanya-shell-sidebar-${position} shivanya-shell-sidebar-${variant} ${collapsed ? "shivanya-shell-sidebar-collapsed" : ""} ${className}`.trim()}
38
+ className={[
39
+ "shivanya-shell-sidebar",
40
+ `shivanya-shell-sidebar-${position}`,
41
+ `shivanya-shell-sidebar-${variant}`,
42
+ collapsed
43
+ ? "shivanya-shell-sidebar-collapsed"
44
+ : "",
45
+ className,
46
+ ]
47
+ .filter(Boolean)
48
+ .join(" ")}
24
49
  style={
25
50
  {
26
51
  "--shivanya-shell-sidebar-width":
27
- typeof width === "number" ? `${width}px` : width,
52
+ typeof width === "number"
53
+ ? `${width}px`
54
+ : width,
28
55
  } as CSSProperties
29
56
  }
30
57
  >
31
58
  {branding && (
32
59
  <div className="shivanya-shell-sidebar-brand">
33
- <ShellBrand branding={branding} compact={collapsed} />
60
+ <ShellBrand
61
+ branding={branding}
62
+ compact={collapsed}
63
+ />
34
64
  </div>
35
65
  )}
66
+
36
67
  {children || (
37
- <nav className="shivanya-shell-nav" aria-label="Primary navigation">
68
+ <Sidebar
69
+ className="shivanya-shell-nav"
70
+ variant="ghost"
71
+ size="md"
72
+ radius="md"
73
+ itemPosition="start"
74
+ >
38
75
  {navigation.map((item, index) => (
39
76
  <ShellNavItemView
40
77
  key={getShellItemKey(item, index)}
@@ -45,9 +82,14 @@ export function ShellSidebar({
45
82
  onNavigate={onNavigate}
46
83
  />
47
84
  ))}
48
- </nav>
85
+ </Sidebar>
86
+ )}
87
+
88
+ {footer && (
89
+ <div className="shivanya-shell-sidebar-footer">
90
+ {footer}
91
+ </div>
49
92
  )}
50
- {footer && <div className="shivanya-shell-sidebar-footer">{footer}</div>}
51
93
  </aside>
52
94
  );
53
95
  }
@@ -65,48 +107,67 @@ function ShellNavItemView({
65
107
  collapsed: boolean;
66
108
  onNavigate?: (item: ShellNavItem) => void;
67
109
  }) {
68
- if (item.divider)
69
- return <div className="shivanya-shell-nav-divider" role="separator" />;
70
- const className =
71
- `shivanya-shell-nav-item ${active ? "is-active" : ""} ${item.disabled ? "is-disabled" : ""}`.trim();
72
- const content = (
110
+ if (item.divider) {
111
+ return (
112
+ <div
113
+ className="shivanya-shell-nav-divider"
114
+ role="separator"
115
+ />
116
+ );
117
+ }
118
+
119
+ const handleClick = () => {
120
+ if (item.disabled) {
121
+ return;
122
+ }
123
+
124
+ item.onClick?.();
125
+ onNavigate?.(item);
126
+ };
127
+
128
+ const rightSection = (
73
129
  <>
74
- <span className="shivanya-shell-nav-icon">{item.icon}</span>
75
- <span className="shivanya-shell-nav-label">{item.label}</span>
76
130
  {!collapsed && item.badge ? (
77
- <span className="shivanya-shell-nav-badge">{item.badge}</span>
131
+ <span className="shivanya-shell-nav-badge">
132
+ {item.badge}
133
+ </span>
78
134
  ) : null}
135
+
79
136
  {!collapsed && item.endIcon ? (
80
- <span className="shivanya-shell-nav-end">{item.endIcon}</span>
137
+ <span className="shivanya-shell-nav-end">
138
+ {item.endIcon}
139
+ </span>
81
140
  ) : null}
82
141
  </>
83
142
  );
84
- const handleClick = () => {
85
- if (!item.disabled) {
86
- item.onClick?.();
87
- onNavigate?.(item);
88
- }
89
- };
90
- if (Link && item.href && !item.disabled)
91
- return (
92
- <Link
93
- className={className}
94
- href={item.href}
95
- onClick={handleClick}
96
- title={collapsed ? String(item.label ?? "") : undefined}
97
- >
98
- {content}
99
- </Link>
100
- );
143
+
101
144
  return (
102
- <button
103
- type="button"
104
- className={className}
145
+ <SidebarItem
146
+ component={Link && item.href && !item.disabled ? Link : "button"}
147
+ href={
148
+ Link && item.href && !item.disabled
149
+ ? item.href
150
+ : undefined
151
+ }
152
+ icon={item.icon}
153
+ rightSection={rightSection}
154
+ active={active}
105
155
  disabled={item.disabled}
106
156
  onClick={handleClick}
107
- title={collapsed ? String(item.label ?? "") : undefined}
157
+ className={[
158
+ "shivanya-shell-nav-item",
159
+ active ? "is-active" : "",
160
+ item.disabled ? "is-disabled" : "",
161
+ ]
162
+ .filter(Boolean)
163
+ .join(" ")}
164
+ title={
165
+ collapsed
166
+ ? String(item.label ?? "")
167
+ : undefined
168
+ }
108
169
  >
109
- {content}
110
- </button>
170
+ {item.label}
171
+ </SidebarItem>
111
172
  );
112
- }
173
+ }