@timmbr/ui 1.0.0-beta → 1.1.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 (100) hide show
  1. package/README.md +20 -16
  2. package/dist/components/Avatar/Avatar.styles.d.ts +1 -1
  3. package/dist/components/Badge/Badge.styles.d.ts +1 -1
  4. package/dist/components/Button/Button.styles.d.ts +2 -2
  5. package/dist/components/Chip/Chip.styles.d.ts +1 -1
  6. package/dist/components/CrossZoneLink/CrossZoneLink.d.ts +10 -0
  7. package/dist/components/CrossZoneLink/CrossZoneLink.d.ts.map +1 -0
  8. package/dist/components/CrossZoneLink/CrossZoneLink.js +111 -0
  9. package/dist/components/CrossZoneLink/CrossZoneLink.styles.d.ts +8 -0
  10. package/dist/components/CrossZoneLink/CrossZoneLink.styles.d.ts.map +1 -0
  11. package/dist/components/CrossZoneLink/CrossZoneLink.styles.js +33 -0
  12. package/dist/components/CrossZoneLink/CrossZoneLink.types.d.ts +31 -0
  13. package/dist/components/CrossZoneLink/CrossZoneLink.types.d.ts.map +1 -0
  14. package/dist/components/CrossZoneLink/index.d.ts +4 -0
  15. package/dist/components/CrossZoneLink/index.d.ts.map +1 -0
  16. package/dist/components/Divider/Divider.styles.d.ts +1 -1
  17. package/dist/components/FormField/FormField.js +3 -3
  18. package/dist/components/Heading/Heading.styles.d.ts +2 -2
  19. package/dist/components/Icon/Icon.styles.d.ts +1 -1
  20. package/dist/components/Inline/Inline.styles.d.ts +2 -2
  21. package/dist/components/Input/Input.js +3 -3
  22. package/dist/components/Input/Input.styles.d.ts +1 -1
  23. package/dist/components/Input/Input.styles.js +1 -1
  24. package/dist/components/Input/Input.types.d.ts +1 -1
  25. package/dist/components/Input/Input.types.d.ts.map +1 -1
  26. package/dist/components/LinkButton/LinkButton.d.ts +13 -0
  27. package/dist/components/LinkButton/LinkButton.d.ts.map +1 -0
  28. package/dist/components/LinkButton/LinkButton.js +179 -0
  29. package/dist/components/LinkButton/LinkButton.styles.d.ts +8 -0
  30. package/dist/components/LinkButton/LinkButton.styles.d.ts.map +1 -0
  31. package/dist/components/LinkButton/LinkButton.styles.js +61 -0
  32. package/dist/components/LinkButton/LinkButton.types.d.ts +60 -0
  33. package/dist/components/LinkButton/LinkButton.types.d.ts.map +1 -0
  34. package/dist/components/LinkButton/index.d.ts +4 -0
  35. package/dist/components/LinkButton/index.d.ts.map +1 -0
  36. package/dist/components/Progress/Progress.styles.d.ts +1 -1
  37. package/dist/components/Radio/Radio.js +3 -3
  38. package/dist/components/Select/Select.js +3 -3
  39. package/dist/components/Select/Select.styles.d.ts +1 -1
  40. package/dist/components/SideBarNavigation/SideBarNavigation.context.d.ts +15 -0
  41. package/dist/components/SideBarNavigation/SideBarNavigation.context.d.ts.map +1 -0
  42. package/dist/components/SideBarNavigation/SideBarNavigation.context.js +10 -0
  43. package/dist/components/SideBarNavigation/SideBarNavigation.d.ts +4 -0
  44. package/dist/components/SideBarNavigation/SideBarNavigation.d.ts.map +1 -0
  45. package/dist/components/SideBarNavigation/SideBarNavigation.helpers.d.ts +19 -0
  46. package/dist/components/SideBarNavigation/SideBarNavigation.helpers.d.ts.map +1 -0
  47. package/dist/components/SideBarNavigation/SideBarNavigation.helpers.js +48 -0
  48. package/dist/components/SideBarNavigation/SideBarNavigation.js +132 -0
  49. package/dist/components/SideBarNavigation/SideBarNavigation.styles.d.ts +18 -0
  50. package/dist/components/SideBarNavigation/SideBarNavigation.styles.d.ts.map +1 -0
  51. package/dist/components/SideBarNavigation/SideBarNavigation.styles.js +85 -0
  52. package/dist/components/SideBarNavigation/SideBarNavigation.types.d.ts +69 -0
  53. package/dist/components/SideBarNavigation/SideBarNavigation.types.d.ts.map +1 -0
  54. package/dist/components/SideBarNavigation/index.d.ts +13 -0
  55. package/dist/components/SideBarNavigation/index.d.ts.map +1 -0
  56. package/dist/components/SideBarNavigation/subcomponents/SidebarBranding.d.ts +13 -0
  57. package/dist/components/SideBarNavigation/subcomponents/SidebarBranding.d.ts.map +1 -0
  58. package/dist/components/SideBarNavigation/subcomponents/SidebarBranding.js +58 -0
  59. package/dist/components/SideBarNavigation/subcomponents/SidebarFooter.d.ts +10 -0
  60. package/dist/components/SideBarNavigation/subcomponents/SidebarFooter.d.ts.map +1 -0
  61. package/dist/components/SideBarNavigation/subcomponents/SidebarFooter.js +27 -0
  62. package/dist/components/SideBarNavigation/subcomponents/SidebarNavItem.d.ts +14 -0
  63. package/dist/components/SideBarNavigation/subcomponents/SidebarNavItem.d.ts.map +1 -0
  64. package/dist/components/SideBarNavigation/subcomponents/SidebarNavItem.js +147 -0
  65. package/dist/components/SideBarNavigation/subcomponents/SidebarPopoverMenu.d.ts +13 -0
  66. package/dist/components/SideBarNavigation/subcomponents/SidebarPopoverMenu.d.ts.map +1 -0
  67. package/dist/components/SideBarNavigation/subcomponents/SidebarPopoverMenu.js +106 -0
  68. package/dist/components/SideBarNavigation/subcomponents/SidebarProfile.d.ts +13 -0
  69. package/dist/components/SideBarNavigation/subcomponents/SidebarProfile.d.ts.map +1 -0
  70. package/dist/components/SideBarNavigation/subcomponents/SidebarProfile.js +118 -0
  71. package/dist/components/SideBarNavigation/subcomponents/SidebarSubItem.d.ts +13 -0
  72. package/dist/components/SideBarNavigation/subcomponents/SidebarSubItem.d.ts.map +1 -0
  73. package/dist/components/SideBarNavigation/subcomponents/SidebarSubItem.js +34 -0
  74. package/dist/components/SideBarNavigation/subcomponents/SidebarToggle.d.ts +8 -0
  75. package/dist/components/SideBarNavigation/subcomponents/SidebarToggle.d.ts.map +1 -0
  76. package/dist/components/SideBarNavigation/subcomponents/SidebarToggle.js +40 -0
  77. package/dist/components/Stack/Stack.styles.d.ts +2 -2
  78. package/dist/components/Tabs/Tabs.styles.d.ts +2 -2
  79. package/dist/components/Text/Text.styles.d.ts +2 -2
  80. package/dist/components/Textarea/Textarea.js +3 -3
  81. package/dist/components/Textarea/Textarea.styles.d.ts +1 -1
  82. package/dist/components/Toast/Toast.d.ts.map +1 -1
  83. package/dist/components/Toast/Toast.js +12 -3
  84. package/dist/components/Toast/Toast.types.d.ts +34 -0
  85. package/dist/components/Toast/Toast.types.d.ts.map +1 -1
  86. package/dist/components/Toast/ToastContainer.d.ts +7 -0
  87. package/dist/components/Toast/ToastContainer.d.ts.map +1 -0
  88. package/dist/components/Toast/ToastContainer.js +104 -0
  89. package/dist/components/Toast/index.d.ts +2 -0
  90. package/dist/components/Toast/index.d.ts.map +1 -1
  91. package/dist/components/Toast/toastStore.d.ts +31 -0
  92. package/dist/components/Toast/toastStore.d.ts.map +1 -0
  93. package/dist/components/Toast/toastStore.js +104 -0
  94. package/dist/index.d.ts +2 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +16 -1
  97. package/dist/providers/TimmbrConfigProvider.d.ts +20 -2
  98. package/dist/providers/TimmbrConfigProvider.d.ts.map +1 -1
  99. package/dist/providers/TimmbrConfigProvider.js +38 -3
  100. package/package.json +14 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SideBarNavigation/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import type { SidebarBrandingConfig } from '../SideBarNavigation.types';
3
+ export interface SidebarBrandingProps {
4
+ branding?: SidebarBrandingConfig;
5
+ collapsed: boolean;
6
+ linkComponent?: React.ComponentType<{
7
+ href: string;
8
+ children: React.ReactNode;
9
+ className?: string;
10
+ }>;
11
+ }
12
+ export declare const SidebarBranding: React.FC<SidebarBrandingProps>;
13
+ //# sourceMappingURL=SidebarBranding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarBranding.d.ts","sourceRoot":"","sources":["../../../../src/components/SideBarNavigation/subcomponents/SidebarBranding.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGxE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuE1D,CAAC"}
@@ -0,0 +1,58 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { AnimatePresence, motion, sidebarContentFadeVariants } from '@timmbr/motion';
4
+ import { cn } from '@timmbr/utils';
5
+ import { useSidebarContext } from '../SideBarNavigation.context.js';
6
+
7
+ const SidebarBranding = ({
8
+ branding,
9
+ collapsed,
10
+ linkComponent: LinkComponent
11
+ }) => {
12
+ const { shouldAnimate } = useSidebarContext();
13
+ const defaultPlaceholder = /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ "data-testid": "sidebar-logo-placeholder",
17
+ className: "size-8 rounded-lg border border-grey-300 bg-grey-100 flex items-center justify-center shrink-0 text-grey-400 text-xs font-semibold",
18
+ children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Logo" })
19
+ }
20
+ );
21
+ const activeLogo = collapsed ? branding?.collapsedLogo || branding?.logo || defaultPlaceholder : branding?.logo || defaultPlaceholder;
22
+ const content = /* @__PURE__ */ jsxs(
23
+ "div",
24
+ {
25
+ className: cn(
26
+ "flex items-center overflow-hidden transition-all duration-200",
27
+ collapsed ? "justify-center py-4 px-2" : "gap-3 px-4 pt-4 pb-2.5"
28
+ ),
29
+ children: [
30
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center justify-center", children: activeLogo }),
31
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: !collapsed && /* @__PURE__ */ jsxs(
32
+ motion.div,
33
+ {
34
+ initial: shouldAnimate ? "hidden" : false,
35
+ animate: shouldAnimate ? "visible" : void 0,
36
+ exit: shouldAnimate ? "exit" : void 0,
37
+ variants: shouldAnimate ? sidebarContentFadeVariants : void 0,
38
+ className: "flex flex-col min-w-0 overflow-hidden whitespace-nowrap",
39
+ children: [
40
+ /* @__PURE__ */ jsx("span", { className: "font-sans font-bold text-base text-grey-900 truncate tracking-tight", children: branding?.title || "Timmbr Console" }),
41
+ branding?.subtitle && /* @__PURE__ */ jsx("span", { className: "font-sans text-xs text-grey-500 truncate", children: branding.subtitle })
42
+ ]
43
+ },
44
+ "sidebar-branding-text"
45
+ ) })
46
+ ]
47
+ }
48
+ );
49
+ if (branding?.href) {
50
+ if (LinkComponent) {
51
+ return /* @__PURE__ */ jsx(LinkComponent, { href: branding.href, className: "block focus-visible:outline-none", children: content });
52
+ }
53
+ return /* @__PURE__ */ jsx("a", { href: branding.href, className: "block focus-visible:outline-none", children: content });
54
+ }
55
+ return content;
56
+ };
57
+
58
+ export { SidebarBranding };
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ export interface SidebarFooterProps {
3
+ footer?: React.ReactNode | ((props: {
4
+ collapsed: boolean;
5
+ }) => React.ReactNode);
6
+ collapsed: boolean;
7
+ className?: string;
8
+ }
9
+ export declare const SidebarFooter: React.FC<SidebarFooterProps>;
10
+ //# sourceMappingURL=SidebarFooter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarFooter.d.ts","sourceRoot":"","sources":["../../../../src/components/SideBarNavigation/subcomponents/SidebarFooter.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChF,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsBtD,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { cn } from '@timmbr/utils';
4
+
5
+ const SidebarFooter = ({
6
+ footer,
7
+ collapsed,
8
+ className
9
+ }) => {
10
+ if (!footer) return null;
11
+ const content = typeof footer === "function" ? footer({ collapsed }) : footer;
12
+ if (!content) return null;
13
+ return /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ "data-testid": "sidebar-footer",
17
+ className: cn(
18
+ "mt-auto border-t border-grey-100 bg-white shrink-0 overflow-hidden",
19
+ collapsed ? "p-2 flex flex-col items-center gap-1" : "p-3",
20
+ className
21
+ ),
22
+ children: content
23
+ }
24
+ );
25
+ };
26
+
27
+ export { SidebarFooter };
@@ -0,0 +1,14 @@
1
+ import * as React from 'react';
2
+ import type { NavItem } from '../SideBarNavigation.types';
3
+ export interface SidebarNavItemProps {
4
+ item: NavItem;
5
+ collapsed: boolean;
6
+ activePath?: string;
7
+ linkComponent?: React.ComponentType<{
8
+ href: string;
9
+ children: React.ReactNode;
10
+ className?: string;
11
+ }>;
12
+ }
13
+ export declare const SidebarNavItem: React.FC<SidebarNavItemProps>;
14
+ //# sourceMappingURL=SidebarNavItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarNavItem.d.ts","sourceRoot":"","sources":["../../../../src/components/SideBarNavigation/subcomponents/SidebarNavItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAO1D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA+KxD,CAAC"}
@@ -0,0 +1,147 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { ChevronDown } from '@timmbr/icons';
5
+ import { cn } from '@timmbr/utils';
6
+ import { AnimatePresence, motion, sidebarAccordionVariants } from '@timmbr/motion';
7
+ import { isNavItemActive, isRouteActive } from '../SideBarNavigation.helpers.js';
8
+ import { navBadgeVariants, navItemVariants } from '../SideBarNavigation.styles.js';
9
+ import { useSidebarContext } from '../SideBarNavigation.context.js';
10
+ import { SidebarSubItem } from './SidebarSubItem.js';
11
+ import { SidebarPopoverMenu } from './SidebarPopoverMenu.js';
12
+ import { Tooltip } from '../../Tooltip/Tooltip.js';
13
+
14
+ const SidebarNavItem = ({
15
+ item,
16
+ collapsed,
17
+ activePath,
18
+ linkComponent: LinkComponent
19
+ }) => {
20
+ const { shouldAnimate } = useSidebarContext();
21
+ const hasSubItems = Boolean(item.items && item.items.length > 0);
22
+ const isActive = isNavItemActive(item, activePath);
23
+ const isDirectActive = isRouteActive(item.href, activePath);
24
+ const [userExpanded, setUserExpanded] = React.useState(null);
25
+ const isExpanded = userExpanded !== null ? userExpanded : isActive;
26
+ if (collapsed) {
27
+ if (hasSubItems) {
28
+ return /* @__PURE__ */ jsx(
29
+ SidebarPopoverMenu,
30
+ {
31
+ item,
32
+ activePath,
33
+ linkComponent: LinkComponent
34
+ }
35
+ );
36
+ }
37
+ const collapsedButton = /* @__PURE__ */ jsxs(
38
+ "button",
39
+ {
40
+ type: "button",
41
+ disabled: item.disabled,
42
+ className: navItemVariants({ active: isDirectActive, collapsed: true }),
43
+ "aria-label": item.label,
44
+ children: [
45
+ /* @__PURE__ */ jsx("span", { className: "size-5 flex items-center justify-center shrink-0", children: item.icon }),
46
+ item.badge !== void 0 && /* @__PURE__ */ jsx(
47
+ "span",
48
+ {
49
+ className: navBadgeVariants({
50
+ variant: item.badgeVariant,
51
+ collapsed: true
52
+ }),
53
+ children: item.badge
54
+ }
55
+ )
56
+ ]
57
+ }
58
+ );
59
+ const buttonWithLink = item.href ? LinkComponent ? /* @__PURE__ */ jsx(LinkComponent, { href: item.href, className: "block w-full", children: collapsedButton }) : /* @__PURE__ */ jsx("a", { href: item.href, className: "block w-full", children: collapsedButton }) : collapsedButton;
60
+ return /* @__PURE__ */ jsx(Tooltip, { content: item.label, side: "right", children: buttonWithLink });
61
+ }
62
+ if (hasSubItems) {
63
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-1", children: [
64
+ /* @__PURE__ */ jsxs(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ onClick: () => setUserExpanded(!isExpanded),
69
+ disabled: item.disabled,
70
+ className: navItemVariants({
71
+ active: isActive && !isExpanded,
72
+ collapsed: false
73
+ }),
74
+ "aria-expanded": isExpanded,
75
+ children: [
76
+ /* @__PURE__ */ jsx("span", { className: "size-5 flex items-center justify-center shrink-0", children: item.icon }),
77
+ /* @__PURE__ */ jsx("span", { className: "truncate flex-1 text-left", children: item.label }),
78
+ item.badge !== void 0 && /* @__PURE__ */ jsx(
79
+ "span",
80
+ {
81
+ className: navBadgeVariants({
82
+ variant: item.badgeVariant,
83
+ collapsed: false
84
+ }),
85
+ children: item.badge
86
+ }
87
+ ),
88
+ /* @__PURE__ */ jsx(
89
+ ChevronDown,
90
+ {
91
+ className: cn(
92
+ "size-4 shrink-0 text-current opacity-70",
93
+ shouldAnimate ? "transition-transform duration-200" : "transition-none",
94
+ isExpanded && "rotate-180"
95
+ )
96
+ }
97
+ )
98
+ ]
99
+ }
100
+ ),
101
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: isExpanded && /* @__PURE__ */ jsx(
102
+ motion.div,
103
+ {
104
+ initial: shouldAnimate ? "hidden" : false,
105
+ animate: shouldAnimate ? "visible" : void 0,
106
+ exit: shouldAnimate ? "exit" : void 0,
107
+ variants: shouldAnimate ? sidebarAccordionVariants : void 0,
108
+ className: "pl-6 pr-1 py-1 space-y-0.5 border-l border-grey-200 ml-5 my-0.5 overflow-hidden",
109
+ children: item.items?.map((sub) => /* @__PURE__ */ jsx(
110
+ SidebarSubItem,
111
+ {
112
+ item: sub,
113
+ activePath,
114
+ linkComponent: LinkComponent
115
+ },
116
+ sub.id || sub.href
117
+ ))
118
+ },
119
+ "sidebar-sub-items"
120
+ ) })
121
+ ] });
122
+ }
123
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
124
+ /* @__PURE__ */ jsx("span", { className: "size-5 flex items-center justify-center shrink-0", children: item.icon }),
125
+ /* @__PURE__ */ jsx("span", { className: "truncate flex-1 text-left", children: item.label }),
126
+ item.badge !== void 0 && /* @__PURE__ */ jsx(
127
+ "span",
128
+ {
129
+ className: navBadgeVariants({
130
+ variant: item.badgeVariant,
131
+ collapsed: false
132
+ }),
133
+ children: item.badge
134
+ }
135
+ )
136
+ ] });
137
+ const className = navItemVariants({ active: isDirectActive, collapsed: false });
138
+ if (item.href) {
139
+ if (LinkComponent) {
140
+ return /* @__PURE__ */ jsx(LinkComponent, { href: item.href, className, children: content });
141
+ }
142
+ return /* @__PURE__ */ jsx("a", { href: item.href, className, children: content });
143
+ }
144
+ return /* @__PURE__ */ jsx("button", { type: "button", disabled: item.disabled, className, children: content });
145
+ };
146
+
147
+ export { SidebarNavItem };
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import type { NavItem } from '../SideBarNavigation.types';
3
+ export interface SidebarPopoverMenuProps {
4
+ item: NavItem;
5
+ activePath?: string;
6
+ linkComponent?: React.ComponentType<{
7
+ href: string;
8
+ children: React.ReactNode;
9
+ className?: string;
10
+ }>;
11
+ }
12
+ export declare const SidebarPopoverMenu: React.FC<SidebarPopoverMenuProps>;
13
+ //# sourceMappingURL=SidebarPopoverMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarPopoverMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/SideBarNavigation/subcomponents/SidebarPopoverMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAM1D,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAuGhE,CAAC"}
@@ -0,0 +1,106 @@
1
+ "use client";
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
5
+ import { cn } from '@timmbr/utils';
6
+ import { isNavItemActive } from '../SideBarNavigation.helpers.js';
7
+ import { navBadgeVariants, navItemVariants } from '../SideBarNavigation.styles.js';
8
+ import { useSidebarContext } from '../SideBarNavigation.context.js';
9
+ import { SidebarSubItem } from './SidebarSubItem.js';
10
+
11
+ const SidebarPopoverMenu = ({
12
+ item,
13
+ activePath,
14
+ linkComponent
15
+ }) => {
16
+ const { shouldAnimate } = useSidebarContext();
17
+ const [open, setOpen] = React.useState(false);
18
+ const timeoutRef = React.useRef(null);
19
+ const handleMouseEnter = () => {
20
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
21
+ setOpen(true);
22
+ };
23
+ const handleMouseLeave = () => {
24
+ timeoutRef.current = setTimeout(() => {
25
+ setOpen(false);
26
+ }, 150);
27
+ };
28
+ React.useEffect(() => {
29
+ return () => {
30
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
31
+ };
32
+ }, []);
33
+ const isActive = isNavItemActive(item, activePath);
34
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(
35
+ "div",
36
+ {
37
+ onMouseEnter: handleMouseEnter,
38
+ onMouseLeave: handleMouseLeave,
39
+ className: "relative flex justify-center",
40
+ children: [
41
+ /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
42
+ "button",
43
+ {
44
+ type: "button",
45
+ className: navItemVariants({ active: isActive, collapsed: true }),
46
+ "aria-expanded": open,
47
+ "aria-label": item.label,
48
+ children: [
49
+ /* @__PURE__ */ jsx("span", { className: "size-5 flex items-center justify-center shrink-0", children: item.icon }),
50
+ item.badge !== void 0 && /* @__PURE__ */ jsx(
51
+ "span",
52
+ {
53
+ className: navBadgeVariants({
54
+ variant: item.badgeVariant,
55
+ collapsed: true
56
+ }),
57
+ children: item.badge
58
+ }
59
+ )
60
+ ]
61
+ }
62
+ ) }),
63
+ /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
64
+ PopoverPrimitive.Content,
65
+ {
66
+ side: "right",
67
+ align: "start",
68
+ sideOffset: 12,
69
+ onMouseEnter: handleMouseEnter,
70
+ onMouseLeave: handleMouseLeave,
71
+ className: cn(
72
+ "z-50 min-w-48 rounded-lg bg-white p-2 text-grey-900 shadow-md border border-grey-200 outline-none animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
73
+ !shouldAnimate && "animate-none transition-none"
74
+ ),
75
+ children: [
76
+ /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 border-b border-grey-100 mb-1 flex items-center justify-between", children: [
77
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-xs text-grey-900 tracking-tight", children: item.label }),
78
+ item.badge !== void 0 && /* @__PURE__ */ jsx(
79
+ "span",
80
+ {
81
+ className: cn(
82
+ "inline-flex items-center justify-center rounded-full px-1.5 py-0.2 text-[10px] font-semibold",
83
+ item.badgeVariant === "destructive" ? "bg-red-500 text-white" : "bg-grey-100 text-grey-800"
84
+ ),
85
+ children: item.badge
86
+ }
87
+ )
88
+ ] }),
89
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col space-y-0.5", children: item.items?.map((sub) => /* @__PURE__ */ jsx(
90
+ SidebarSubItem,
91
+ {
92
+ item: sub,
93
+ activePath,
94
+ linkComponent
95
+ },
96
+ sub.id || sub.href
97
+ )) })
98
+ ]
99
+ }
100
+ ) })
101
+ ]
102
+ }
103
+ ) });
104
+ };
105
+
106
+ export { SidebarPopoverMenu };
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import type { SidebarProfileConfig } from '../SideBarNavigation.types';
3
+ export interface SidebarProfileProps {
4
+ profile?: SidebarProfileConfig;
5
+ collapsed: boolean;
6
+ linkComponent?: React.ComponentType<{
7
+ href: string;
8
+ children: React.ReactNode;
9
+ className?: string;
10
+ }>;
11
+ }
12
+ export declare const SidebarProfile: React.FC<SidebarProfileProps>;
13
+ //# sourceMappingURL=SidebarProfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarProfile.d.ts","sourceRoot":"","sources":["../../../../src/components/SideBarNavigation/subcomponents/SidebarProfile.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAIvE,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAkMxD,CAAC"}
@@ -0,0 +1,118 @@
1
+ "use client";
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
4
+ import { ChevronsUpDown } from '@timmbr/icons';
5
+ import { cn } from '@timmbr/utils';
6
+ import { AnimatePresence, motion, sidebarContentFadeVariants } from '@timmbr/motion';
7
+ import { useSidebarContext } from '../SideBarNavigation.context.js';
8
+ import { Tooltip } from '../../Tooltip/Tooltip.js';
9
+
10
+ const SidebarProfile = ({
11
+ profile,
12
+ collapsed,
13
+ linkComponent: LinkComponent
14
+ }) => {
15
+ const { shouldAnimate } = useSidebarContext();
16
+ if (!profile) return null;
17
+ const fallbackInitials = profile.fallback || profile.name.split(" ").map((part) => part[0]).join("").slice(0, 2).toUpperCase();
18
+ const avatarElement = profile.avatar ? /* @__PURE__ */ jsx("div", { className: "size-8 rounded-full overflow-hidden shrink-0 flex items-center justify-center", children: profile.avatar }) : /* @__PURE__ */ jsx("div", { className: "size-8 rounded-full bg-grey-200 border border-grey-300 flex items-center justify-center shrink-0 font-medium text-xs text-grey-700", children: fallbackInitials });
19
+ const hasItems = Boolean(profile.items && profile.items.length > 0);
20
+ const menuContent = hasItems && /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
21
+ DropdownMenuPrimitive.Content,
22
+ {
23
+ side: collapsed ? "right" : "top",
24
+ align: collapsed ? "end" : "center",
25
+ sideOffset: collapsed ? 12 : 8,
26
+ className: cn(
27
+ "z-50 min-w-56 rounded-lg bg-white p-1.5 text-grey-900 shadow-md border border-grey-200 outline-none animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
28
+ !shouldAnimate && "animate-none transition-none"
29
+ ),
30
+ children: [
31
+ /* @__PURE__ */ jsxs("div", { className: "px-2.5 py-2 border-b border-grey-100 mb-1", children: [
32
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-xs text-grey-900 truncate", children: profile.name }),
33
+ profile.email && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-grey-500 truncate mt-0.5", children: profile.email })
34
+ ] }),
35
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: profile.items?.map((item) => {
36
+ const itemContent = /* @__PURE__ */ jsxs(Fragment, { children: [
37
+ item.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0 size-4 flex items-center justify-center", children: item.icon }),
38
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label })
39
+ ] });
40
+ const itemClass = cn(
41
+ "flex items-center gap-2.5 w-full rounded-md px-2.5 py-1.5 text-xs transition-colors duration-150 select-none cursor-pointer outline-none focus-visible:bg-grey-100",
42
+ item.destructive ? "text-red-600 hover:bg-red-50 hover:text-red-700" : "text-grey-700 hover:bg-grey-100 hover:text-grey-900",
43
+ item.disabled && "opacity-50 pointer-events-none"
44
+ );
45
+ if (item.href) {
46
+ return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Item, { asChild: true, children: LinkComponent ? /* @__PURE__ */ jsx(LinkComponent, { href: item.href, className: itemClass, children: itemContent }) : /* @__PURE__ */ jsx("a", { href: item.href, className: itemClass, children: itemContent }) }, item.id || item.href);
47
+ }
48
+ return /* @__PURE__ */ jsx(
49
+ DropdownMenuPrimitive.Item,
50
+ {
51
+ onSelect: item.onClick,
52
+ disabled: item.disabled,
53
+ className: itemClass,
54
+ children: itemContent
55
+ },
56
+ item.id || item.label
57
+ );
58
+ }) })
59
+ ]
60
+ }
61
+ ) });
62
+ if (collapsed) {
63
+ const collapsedTrigger = /* @__PURE__ */ jsx(
64
+ "button",
65
+ {
66
+ type: "button",
67
+ "data-testid": "sidebar-profile-btn",
68
+ onClick: !hasItems ? profile.onClick : void 0,
69
+ className: "size-9 rounded-full flex items-center justify-center hover:ring-2 hover:ring-primary/20 transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
70
+ "aria-label": profile.name,
71
+ children: avatarElement
72
+ }
73
+ );
74
+ if (hasItems) {
75
+ return /* @__PURE__ */ jsx("div", { className: "py-2 flex justify-center border-t border-grey-200", children: /* @__PURE__ */ jsxs(DropdownMenuPrimitive.Root, { children: [
76
+ /* @__PURE__ */ jsx(DropdownMenuPrimitive.Trigger, { asChild: true, children: collapsedTrigger }),
77
+ menuContent
78
+ ] }) });
79
+ }
80
+ return /* @__PURE__ */ jsx("div", { className: "py-2 flex justify-center border-t border-grey-200", children: /* @__PURE__ */ jsx(Tooltip, { content: profile.name, side: "right", children: collapsedTrigger }) });
81
+ }
82
+ const expandedTrigger = /* @__PURE__ */ jsxs(
83
+ "button",
84
+ {
85
+ type: "button",
86
+ "data-testid": "sidebar-profile-btn",
87
+ onClick: !hasItems ? profile.onClick : void 0,
88
+ className: "flex items-center gap-3 w-full p-2 rounded-lg text-left hover:bg-grey-100 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary overflow-hidden",
89
+ children: [
90
+ avatarElement,
91
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: !collapsed && /* @__PURE__ */ jsxs(
92
+ motion.div,
93
+ {
94
+ initial: shouldAnimate ? "hidden" : false,
95
+ animate: shouldAnimate ? "visible" : void 0,
96
+ exit: shouldAnimate ? "exit" : void 0,
97
+ variants: shouldAnimate ? sidebarContentFadeVariants : void 0,
98
+ className: "flex items-center min-w-0 flex-1 overflow-hidden",
99
+ children: [
100
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1 overflow-hidden", children: [
101
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-xs text-grey-900 truncate", children: profile.name }),
102
+ profile.email && /* @__PURE__ */ jsx("span", { className: "text-[11px] text-grey-500 truncate block", children: profile.email })
103
+ ] }),
104
+ hasItems && /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-4 text-grey-400 shrink-0 ml-auto" })
105
+ ]
106
+ },
107
+ "profile-text-details"
108
+ ) })
109
+ ]
110
+ }
111
+ );
112
+ return /* @__PURE__ */ jsx("div", { className: "p-3 border-t border-grey-200 bg-white shrink-0 overflow-hidden", children: hasItems ? /* @__PURE__ */ jsxs(DropdownMenuPrimitive.Root, { children: [
113
+ /* @__PURE__ */ jsx(DropdownMenuPrimitive.Trigger, { asChild: true, children: expandedTrigger }),
114
+ menuContent
115
+ ] }) : expandedTrigger });
116
+ };
117
+
118
+ export { SidebarProfile };
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import type { NavSubItem } from '../SideBarNavigation.types';
3
+ export interface SidebarSubItemProps {
4
+ item: NavSubItem;
5
+ activePath?: string;
6
+ linkComponent?: React.ComponentType<{
7
+ href: string;
8
+ children: React.ReactNode;
9
+ className?: string;
10
+ }>;
11
+ }
12
+ export declare const SidebarSubItem: React.FC<SidebarSubItemProps>;
13
+ //# sourceMappingURL=SidebarSubItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarSubItem.d.ts","sourceRoot":"","sources":["../../../../src/components/SideBarNavigation/subcomponents/SidebarSubItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAI7D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA6CxD,CAAC"}
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
+ import { cn } from '@timmbr/utils';
4
+ import { isRouteActive } from '../SideBarNavigation.helpers.js';
5
+ import { subItemVariants } from '../SideBarNavigation.styles.js';
6
+
7
+ const SidebarSubItem = ({
8
+ item,
9
+ activePath,
10
+ linkComponent: LinkComponent
11
+ }) => {
12
+ const isActive = isRouteActive(item.href, activePath);
13
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
14
+ item.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0 size-4 flex items-center justify-center", children: item.icon }),
15
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: item.label }),
16
+ item.badge !== void 0 && /* @__PURE__ */ jsx(
17
+ "span",
18
+ {
19
+ className: cn(
20
+ "ml-auto inline-flex items-center justify-center rounded-full px-1.5 py-0.2 text-[10px] font-semibold",
21
+ item.badgeVariant === "destructive" ? "bg-red-500 text-white" : "bg-grey-200 text-grey-800"
22
+ ),
23
+ children: item.badge
24
+ }
25
+ )
26
+ ] });
27
+ const className = subItemVariants({ active: isActive });
28
+ if (LinkComponent) {
29
+ return /* @__PURE__ */ jsx(LinkComponent, { href: item.href, className, children: content });
30
+ }
31
+ return /* @__PURE__ */ jsx("a", { href: item.href, className, children: content });
32
+ };
33
+
34
+ export { SidebarSubItem };
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ export interface SidebarToggleProps {
3
+ collapsed: boolean;
4
+ onToggle: () => void;
5
+ className?: string;
6
+ }
7
+ export declare const SidebarToggle: React.FC<SidebarToggleProps>;
8
+ //# sourceMappingURL=SidebarToggle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarToggle.d.ts","sourceRoot":"","sources":["../../../../src/components/SideBarNavigation/subcomponents/SidebarToggle.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4BtD,CAAC"}