@dbcdk/react-components 0.0.9 → 0.0.12

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 (113) hide show
  1. package/dist/components/accordion/Accordion.d.ts +27 -0
  2. package/dist/components/accordion/Accordion.js +66 -0
  3. package/dist/components/accordion/Accordion.module.css +87 -0
  4. package/dist/components/button/Button.module.css +1 -0
  5. package/dist/components/card/Card.d.ts +21 -3
  6. package/dist/components/card/Card.js +17 -2
  7. package/dist/components/card/Card.module.css +59 -0
  8. package/dist/components/circle/Circle.d.ts +5 -1
  9. package/dist/components/circle/Circle.js +2 -2
  10. package/dist/components/circle/Circle.module.css +60 -4
  11. package/dist/components/code-block/CodeBlock.js +1 -1
  12. package/dist/components/code-block/CodeBlock.module.css +30 -17
  13. package/dist/components/copy-button/CopyButton.d.ts +1 -0
  14. package/dist/components/copy-button/CopyButton.js +10 -2
  15. package/dist/components/datetime-picker/DateTimePicker.d.ts +4 -8
  16. package/dist/components/datetime-picker/DateTimePicker.js +72 -92
  17. package/dist/components/datetime-picker/dateTimeHelpers.d.ts +14 -12
  18. package/dist/components/datetime-picker/dateTimeHelpers.js +25 -45
  19. package/dist/components/filter-field/FilterField.js +16 -11
  20. package/dist/components/filter-field/FilterField.module.css +133 -12
  21. package/dist/components/forms/checkbox/Checkbox.d.ts +4 -10
  22. package/dist/components/forms/checkbox/Checkbox.js +3 -5
  23. package/dist/components/forms/checkbox-group/CheckboxGroup.js +1 -1
  24. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +1 -1
  25. package/dist/components/forms/input/Input.d.ts +1 -0
  26. package/dist/components/forms/input/Input.js +2 -4
  27. package/dist/components/forms/input/Input.module.css +10 -11
  28. package/dist/components/forms/input-container/InputContainer.d.ts +2 -1
  29. package/dist/components/forms/input-container/InputContainer.js +3 -3
  30. package/dist/components/forms/input-container/InputContainer.module.css +65 -0
  31. package/dist/components/forms/radio-buttons/RadioButton.d.ts +36 -0
  32. package/dist/components/forms/radio-buttons/RadioButton.js +26 -0
  33. package/dist/components/forms/radio-buttons/RadioButtonGroup.d.ts +25 -0
  34. package/dist/components/forms/radio-buttons/RadioButtonGroup.js +19 -0
  35. package/dist/components/forms/radio-buttons/RadioButtons.module.css +117 -0
  36. package/dist/components/forms/select/Select.d.ts +1 -1
  37. package/dist/components/forms/select/Select.js +3 -3
  38. package/dist/components/forms/text-area/Textarea.js +3 -3
  39. package/dist/components/forms/text-area/Textarea.module.css +8 -1
  40. package/dist/components/headline/Headline.d.ts +2 -7
  41. package/dist/components/headline/Headline.js +5 -2
  42. package/dist/components/headline/Headline.module.css +61 -2
  43. package/dist/components/hyperlink/Hyperlink.d.ts +19 -6
  44. package/dist/components/hyperlink/Hyperlink.js +35 -7
  45. package/dist/components/hyperlink/Hyperlink.module.css +50 -2
  46. package/dist/components/icon/Icon.module.css +1 -0
  47. package/dist/components/interval-select/IntervalSelect.js +1 -1
  48. package/dist/components/menu/Menu.d.ts +32 -0
  49. package/dist/components/menu/Menu.js +73 -13
  50. package/dist/components/menu/Menu.module.css +72 -4
  51. package/dist/components/nav-bar/NavBar.d.ts +24 -6
  52. package/dist/components/overlay/modal/Modal.module.css +2 -2
  53. package/dist/components/overlay/side-panel/SidePanel.d.ts +12 -4
  54. package/dist/components/overlay/side-panel/SidePanel.js +77 -4
  55. package/dist/components/overlay/side-panel/SidePanel.module.css +149 -28
  56. package/dist/components/overlay/side-panel/useSidePanel.d.ts +1 -1
  57. package/dist/components/overlay/side-panel/useSidePanel.js +2 -2
  58. package/dist/components/overlay/tooltip/useTooltipTrigger.js +4 -2
  59. package/dist/components/page-layout/PageLayout.js +0 -2
  60. package/dist/components/popover/Popover.js +1 -1
  61. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +5 -5
  62. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +36 -24
  63. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -3
  64. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -1
  65. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +4 -3
  66. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +109 -79
  67. package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +16 -3
  68. package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +20 -0
  69. package/dist/components/sidebar/providers/SidebarProvider.d.ts +4 -1
  70. package/dist/components/sidebar/providers/SidebarProvider.js +85 -58
  71. package/dist/components/skeleton-loader/SkeletonLoader.d.ts +1 -1
  72. package/dist/components/skeleton-loader/SkeletonLoader.js +15 -12
  73. package/dist/components/split-button/SplitButton.d.ts +1 -1
  74. package/dist/components/split-button/SplitButton.js +3 -1
  75. package/dist/components/split-button/SplitButton.module.css +4 -4
  76. package/dist/components/state-page/StatePage.d.ts +9 -0
  77. package/dist/components/state-page/StatePage.js +20 -0
  78. package/dist/components/state-page/StatePage.module.css +9 -0
  79. package/dist/components/state-page/empty.d.ts +2 -0
  80. package/dist/components/state-page/empty.js +2 -0
  81. package/dist/components/state-page/error.d.ts +2 -0
  82. package/dist/components/state-page/error.js +2 -0
  83. package/dist/components/state-page/notFound.d.ts +2 -0
  84. package/dist/components/state-page/notFound.js +2 -0
  85. package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +19 -0
  86. package/dist/components/sticky-footer-layout/StickyFooterLayout.js +27 -0
  87. package/dist/components/table/Table.d.ts +9 -4
  88. package/dist/components/table/Table.js +6 -9
  89. package/dist/components/table/Table.module.css +180 -59
  90. package/dist/components/table/components/empty-state/EmptyState.d.ts +1 -1
  91. package/dist/components/table/components/empty-state/EmptyState.js +6 -7
  92. package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -3
  93. package/dist/components/table/components/table-settings/TableSettings.js +55 -4
  94. package/dist/components/table/tanstack.d.ts +12 -1
  95. package/dist/components/table/tanstack.js +75 -23
  96. package/dist/components/toast/Toast.js +5 -1
  97. package/dist/components/toast/Toast.module.css +40 -15
  98. package/dist/components/toast/provider/ToastProvider.js +1 -0
  99. package/dist/hooks/useTableSettings.d.ts +23 -4
  100. package/dist/hooks/useTableSettings.js +64 -17
  101. package/dist/hooks/useTimeDuration.js +9 -3
  102. package/dist/hooks/useViewportFill.js +1 -0
  103. package/dist/index.d.ts +6 -0
  104. package/dist/index.js +6 -1
  105. package/dist/src/styles/styles.css +60 -25
  106. package/dist/styles/animation.d.ts +5 -0
  107. package/dist/styles/animation.js +5 -0
  108. package/dist/styles/styles.css +60 -25
  109. package/dist/styles/themes/dbc/dark.css +1 -1
  110. package/dist/styles/themes/dbc/light.css +2 -1
  111. package/dist/utils/localStorage.utils.d.ts +19 -0
  112. package/dist/utils/localStorage.utils.js +78 -0
  113. package/package.json +1 -1
@@ -1,54 +1,66 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { ChevronDown } from 'lucide-react';
4
- import { useCallback, useEffect, useState } from 'react';
4
+ import { useCallback, useEffect, useMemo, useState } from 'react';
5
5
  import styles from './ExpandableSidebarItem.module.css';
6
6
  import { Button } from '../../../button/Button';
7
7
  import { useSidebar } from '../../providers/SidebarProvider';
8
+ import { ExpandableSidebarItem as ExpandableChild } from '../expandable-sidebar-item/ExpandableSidebarItem';
8
9
  import { SidebarItemContent } from '../sidebar-item-content/SidebarItemContent';
9
10
  import { SidebarItem } from '../SidebarItem';
11
+ const isGroup = (item) => item.type === 'group';
12
+ const isExpandable = (item) => item.type === 'expandable';
10
13
  export function ExpandableSidebarItem({ items, label, icon, component: Component, href, }) {
11
- const { defaultExpanded, resetExpandAll, isSidebarCollapsed, handleSidebarCollapseChange, expandedItems, } = useSidebar();
12
- const [expanded, setExpanded] = useState(false);
14
+ const { defaultExpanded, resetExpandAll, isSidebarCollapsed, handleSidebarCollapseChange, expandItem, collapseItem, isExpanded, } = useSidebar();
15
+ // Local-only state for animation coordination
13
16
  const [closing, setClosing] = useState(false);
14
17
  const [ready, setReady] = useState(false);
15
18
  useEffect(() => {
16
19
  setReady(true);
17
20
  }, []);
21
+ // Single source of truth: expanded comes from provider state
22
+ const expanded = useMemo(() => isExpanded(href), [href, isExpanded]);
23
+ // Expand-all behavior (e.g. search)
18
24
  useEffect(() => {
19
- if (expandedItems.has(href)) {
20
- setExpanded(true);
21
- }
22
- }, [expandedItems, href]);
23
- useEffect(() => {
24
- if (defaultExpanded === null) {
25
+ if (defaultExpanded === null)
25
26
  return;
26
- }
27
- setExpanded(defaultExpanded);
28
- }, [defaultExpanded]);
27
+ if (defaultExpanded)
28
+ expandItem(href);
29
+ else
30
+ collapseItem(href);
31
+ }, [defaultExpanded, expandItem, collapseItem, href]);
29
32
  const handleAnimationEnd = useCallback(() => {
30
- if (ready) {
31
- setExpanded(!closing);
33
+ if (!ready)
34
+ return;
35
+ if (closing) {
36
+ // After collapse animation, commit closed state
37
+ collapseItem(href);
32
38
  setClosing(false);
33
39
  }
34
- }, [closing, ready]);
40
+ }, [closing, ready, collapseItem, href]);
35
41
  const toggleAccordion = useCallback((e, onlyExpand = false) => {
36
42
  e === null || e === void 0 ? void 0 : e.preventDefault();
37
43
  e === null || e === void 0 ? void 0 : e.stopPropagation();
38
44
  resetExpandAll();
39
- handleSidebarCollapseChange === null || handleSidebarCollapseChange === void 0 ? void 0 : handleSidebarCollapseChange(false);
45
+ handleSidebarCollapseChange(false);
40
46
  if (!expanded) {
41
- setExpanded(true);
47
+ expandItem(href);
42
48
  return;
43
49
  }
44
50
  if (!isSidebarCollapsed && !onlyExpand) {
51
+ // Start collapse animation; state commit happens onAnimationEnd
45
52
  setClosing(true);
46
53
  }
47
- }, [expanded, handleSidebarCollapseChange, isSidebarCollapsed, resetExpandAll]);
48
- if (!items)
49
- return null;
50
- if (!Component) {
51
- return null;
52
- }
53
- return (_jsxs("div", { className: `${styles.container} ${expanded ? styles.expanded : ''}`, children: [_jsx(Component, { onClick: () => toggleAccordion(undefined, true), children: _jsx(SidebarItemContent, { icon: icon, label: label, href: href, disableActiveStyles: expanded, suffixIcon: isSidebarCollapsed ? null : (_jsx(Button, { variant: "outlined", onClick: toggleAccordion, children: _jsx(ChevronDown, { className: `${styles.chevron} ${expanded ? styles.chevronExpanded : ''}` }) })) }) }), expanded && !isSidebarCollapsed && (_jsx("div", { onAnimationEnd: handleAnimationEnd, className: `${styles.childrenContainer} ${closing ? 'animate--collapse' : ''} ${expanded ? 'animate--expand' : 'visually-hidden'}`, children: items.map(({ component: Component, label, icon, href }, id) => (_jsx(SidebarItem, { component: Component, label: label, icon: icon, href: href }, id))) }))] }));
54
+ }, [expanded, expandItem, href, handleSidebarCollapseChange, isSidebarCollapsed, resetExpandAll]);
55
+ const renderNavItem = (item, key) => {
56
+ var _a, _b;
57
+ if (isGroup(item)) {
58
+ return (_jsxs("div", { className: styles.group, children: [_jsx("div", { className: styles.groupLabel, children: item.label }), (_a = item.children) === null || _a === void 0 ? void 0 : _a.map((child, idx) => renderNavItem(child, `${key}-${idx}`))] }, key));
59
+ }
60
+ if (isExpandable(item)) {
61
+ return (_jsx(ExpandableChild, { items: (_b = item.children) !== null && _b !== void 0 ? _b : [], label: item.label, icon: item.icon, href: item.href, component: item.component }, key));
62
+ }
63
+ return (_jsx(SidebarItem, { component: item.component, label: item.label, icon: item.icon, href: item.href }, key));
64
+ };
65
+ return (_jsxs("div", { className: `${styles.container} ${expanded ? styles.expanded : ''}`, children: [_jsx(Component, { onClick: () => toggleAccordion(undefined, true), children: _jsx(SidebarItemContent, { icon: icon, label: label, href: href, disableActiveStyles: expanded, suffixIcon: isSidebarCollapsed ? null : (_jsx(Button, { variant: "outlined", onClick: toggleAccordion, children: _jsx(ChevronDown, { className: `${styles.chevron} ${expanded ? styles.chevronExpanded : ''}` }) })) }) }), expanded && !isSidebarCollapsed && (_jsx("div", { onAnimationEnd: handleAnimationEnd, className: `${styles.childrenContainer} ${closing ? 'animate--collapse' : ''} ${expanded ? 'animate--expand' : 'visually-hidden'}`, children: items.map((item, idx) => renderNavItem(item, `${href}-${idx}`)) }))] }));
54
66
  }
@@ -1,6 +1,3 @@
1
- .button {
2
- }
3
-
4
1
  .container {
5
2
  position: relative;
6
3
  display: flex;
@@ -5,5 +5,7 @@ interface SidebarContainerProps {
5
5
  productLogo?: ReactNode;
6
6
  activeLink?: string;
7
7
  }
8
- export declare function SidebarContainer({ logo, productName, productLogo, activeLink, }: SidebarContainerProps): JSX.Element;
8
+ export declare function SidebarContainer({ logo, // DBC Digital (company)
9
+ productLogo, // DataIO (product)
10
+ activeLink, }: SidebarContainerProps): JSX.Element;
9
11
  export {};
@@ -2,12 +2,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ChevronLeft } from 'lucide-react';
3
3
  import { Logo } from '../../../../assets/logo';
4
4
  import { Button } from '../../../../components/button/Button';
5
- import { Headline } from '../../../../components/headline/Headline';
6
5
  import { SidebarItems } from '../../../../components/sidebar/components/sidebar-items/SidebarItems';
7
6
  import SidenavFiltering from '../../../../components/sidebar/components/sidenav-filteirng/SidenavFiltering';
8
7
  import { useSidebar } from '../../../../components/sidebar/providers/SidebarProvider';
9
8
  import styles from './SidebarContainer.module.css';
10
- export function SidebarContainer({ logo, productName, productLogo, activeLink, }) {
9
+ export function SidebarContainer({ logo, // DBC Digital (company)
10
+ productLogo, // DataIO (product)
11
+ activeLink, }) {
11
12
  const { isSidebarCollapsed, handleSidebarCollapseChange } = useSidebar();
12
- return (_jsxs("div", { className: `${styles.container} ${isSidebarCollapsed ? styles.collapsed : ''}`, children: [_jsxs("div", { className: styles.header, children: [_jsxs("span", { className: styles.logoContainer, children: [_jsx("div", { style: { textAlign: isSidebarCollapsed ? 'center' : 'right' }, children: _jsx(Button, { size: "sm", variant: "inline", icon: _jsx(ChevronLeft, { className: isSidebarCollapsed ? styles.collapsedIcon : '' }), onClick: () => handleSidebarCollapseChange(!isSidebarCollapsed) }) }), _jsx("div", { className: styles.logo, children: logo !== null && logo !== void 0 ? logo : _jsx(Logo, {}) })] }), productName && _jsx(Headline, { disableMargin: true, children: productName }), productLogo && _jsx("div", { className: styles.productLogo, children: productLogo })] }), _jsxs("div", { className: styles.content, children: [_jsx("div", { className: styles.filter, children: _jsx(SidenavFiltering, {}) }), _jsx("div", { className: `${styles.links} hideScrollBar`, children: _jsx(SidebarItems, { activeLink: activeLink }) })] }), _jsx("div", { className: styles.footer })] }));
13
+ return (_jsxs("div", { className: `${styles.container} ${isSidebarCollapsed ? styles.collapsed : ''}`, children: [_jsx("div", { className: styles.header, children: _jsxs("div", { className: styles.productHeader, children: [_jsx("div", { className: styles.productLogo, children: productLogo }), _jsx(Button, { size: "md", variant: "inline", "aria-label": "Collapse sidebar", icon: _jsx(ChevronLeft, { className: isSidebarCollapsed ? styles.collapsedIcon : '' }), onClick: () => handleSidebarCollapseChange(!isSidebarCollapsed) })] }) }), _jsxs("div", { className: styles.content, children: [_jsx("div", { className: styles.filter, children: _jsx(SidenavFiltering, {}) }), _jsx("div", { className: `${styles.links} hideScrollBar`, children: _jsx(SidebarItems, { activeLink: activeLink }) })] }), _jsx("div", { className: styles.footer, children: _jsx("div", { className: styles.companyLogo, children: logo !== null && logo !== void 0 ? logo : _jsx(Logo, {}) }) })] }));
13
14
  }
@@ -4,152 +4,182 @@
4
4
  overflow: auto;
5
5
  display: flex;
6
6
  flex-direction: column;
7
- gap: var(--spacing-lg);
7
+ gap: var(--spacing-md);
8
8
  width: var(--sidebar-width);
9
9
  inline-size: var(--sidebar-width);
10
10
  box-sizing: border-box;
11
11
  border-inline-end: var(--border-width-thin) solid var(--color-border-default);
12
- padding-bottom: var(--spacing-lg);
12
+
13
13
  transition:
14
14
  width var(--transition-fast) var(--ease-standard),
15
15
  inline-size var(--transition-fast) var(--ease-standard);
16
16
  }
17
17
 
18
+ /* Collapsed state */
18
19
  .container.collapsed {
19
20
  width: var(--component-size-lg);
20
21
  inline-size: var(--component-size-lg);
21
22
  box-sizing: content-box;
22
23
  gap: var(--spacing-sm);
23
- .content {
24
- gap: var(--spacing-2xs);
25
- }
26
24
  }
27
25
 
28
- .container .logoContainer button,
29
- .container .filter button {
30
- border-radius: 0;
31
- min-height: var(--component-size-md);
32
- width: 100%;
33
- padding: var(--spacing-xs);
34
- color: var(--color-fg-muted);
26
+ /* Global links / focus */
27
+ .container a {
28
+ text-decoration: none;
29
+ color: inherit;
35
30
  }
36
31
 
37
- .container:not(.collapsed) .links,
38
- .container:not(.collapsed) .filter {
39
- padding-inline: var(--spacing-sm);
32
+ .container a:focus-visible,
33
+ .container button:focus-visible {
34
+ outline: none;
35
+ box-shadow: var(--focus-ring);
40
36
  }
41
37
 
42
- .container .logoContainer {
43
- padding-top: var(--spacing-xs);
44
- min-block-size: 60px;
38
+ /* HEADER (product + collapse) */
39
+ .header {
40
+ flex: 0 0 auto;
45
41
  border-bottom: 1px solid var(--color-border-default);
46
- padding-bottom: var(--spacing-xxs);
42
+ padding: 0 var(--spacing-sm);
43
+ min-block-size: 60px;
44
+ display: flex;
45
+ justify-content: space-between;
47
46
  }
48
47
 
49
- .container.collapsed .logoContainer {
48
+ .productHeader {
50
49
  display: flex;
51
- flex-direction: column;
52
50
  align-items: center;
53
- justify-content: center;
51
+ justify-content: space-between;
52
+ gap: var(--spacing-sm);
53
+ flex-grow: 1;
54
54
  }
55
55
 
56
- .container:not(.collapsed) .logoContainer {
56
+ /* Product logo container */
57
+ .productLogo {
57
58
  display: flex;
58
59
  align-items: center;
59
- flex-direction: row-reverse;
60
- justify-content: space-between;
61
- padding-right: var(--spacing-xxs);
60
+ max-inline-size: 100%;
61
+ min-width: 0;
62
62
  }
63
63
 
64
- .container a {
65
- text-decoration: none;
66
- color: inherit;
64
+ /* Keep product logo visible in expanded state */
65
+ .productLogo img,
66
+ .productLogo svg {
67
+ inline-size: 50px;
68
+ max-inline-size: 100%;
69
+ block-size: auto;
67
70
  }
68
71
 
69
- .container .links button {
70
- background: none;
71
- border: 0;
72
- font-size: inherit;
73
- color: inherit;
74
- display: inline-flex;
75
- padding: 0;
72
+ /* Collapse button */
73
+ .productHeader button {
74
+ border-radius: 0;
75
+ min-height: var(--component-size-md);
76
+ padding: var(--spacing-xs);
77
+ color: var(--color-fg-muted);
78
+ flex: 0 0 auto;
76
79
  }
77
80
 
78
- .container a:focus-visible,
79
- .container button:focus-visible {
80
- outline: none;
81
- box-shadow: var(--focus-ring);
81
+ /* Rotate icon when collapsed */
82
+ .collapsedIcon {
83
+ transform: rotate(180deg);
84
+ transition: transform 0.3s ease;
82
85
  }
83
86
 
87
+ /* CONTENT */
88
+ .content {
89
+ overflow: auto;
90
+ flex: 1 1 auto;
91
+ overflow-y: visible;
92
+ display: flex;
93
+ flex-direction: column;
94
+ position: relative;
95
+ width: 100%;
96
+ gap: 5px;
97
+ }
98
+
99
+ .container:not(.collapsed) .content {
100
+ gap: var(--spacing-md);
101
+ }
102
+
103
+ /* FILTER */
104
+ .filter button {
105
+ border-radius: 0;
106
+ min-height: var(--component-size-md);
107
+ width: 100%;
108
+ padding: var(--spacing-xs);
109
+ color: var(--color-fg-muted);
110
+ }
111
+
112
+ .container:not(.collapsed) .filter {
113
+ padding-inline: var(--spacing-xs);
114
+ }
115
+
116
+ /* LINKS */
84
117
  .links {
85
118
  overflow: auto;
86
119
  display: flex;
87
120
  flex-grow: 1;
88
- overflow: auto;
89
121
  flex-direction: column;
90
122
  gap: 2px;
91
123
  font-size: var(--font-size-sm);
92
124
  }
93
125
 
94
126
  .container:not(.collapsed) .links {
95
- padding-inline: var(--spacing-sm);
127
+ padding-inline: var(--spacing-xs);
96
128
  }
97
129
 
98
- .header {
130
+ .container .links button {
131
+ background: none;
132
+ border: 0;
133
+ font-size: inherit;
134
+ color: inherit;
135
+ display: inline-flex;
136
+ padding: 0;
137
+ }
138
+
139
+ /* FOOTER (company logo) */
140
+ .footer {
99
141
  flex: 0 0 auto;
142
+ border-top: 1px solid var(--color-border-default);
143
+ padding: var(--spacing-sm);
100
144
  display: flex;
101
- flex-direction: column;
145
+ justify-content: center;
102
146
  }
103
147
 
104
- .container:not(.collapsed) .header {
105
- gap: var(--spacing-sm);
148
+ .companyLogo {
149
+ opacity: 0.6;
106
150
  }
107
151
 
108
- .container:not(.collapsed) .logo {
109
- padding: 0 var(--spacing-sm);
152
+ .companyLogo svg {
153
+ width: 80px;
154
+ height: auto;
155
+ display: block;
110
156
  }
111
- .container.collapsed .logo {
157
+
158
+ /* Hide company logo in collapsed state */
159
+ .container.collapsed .companyLogo {
112
160
  display: none;
113
161
  }
114
162
 
115
- .logo img,
116
- .logo svg {
117
- inline-size: 50px;
118
- max-inline-size: 100%;
119
- block-size: auto;
163
+ .logo {
164
+ display: none;
120
165
  }
121
166
 
167
+ /* === Collapsed header behavior ===
168
+ Hide product logo entirely so the collapse button can truly center. */
122
169
  .container.collapsed .productLogo {
123
170
  display: none;
124
171
  }
125
- .productLogo {
126
- max-inline-size: 100%;
127
- padding: 0 var(--spacing-sm);
128
- }
129
172
 
130
- .productLogo svg {
131
- max-inline-size: 100%;
132
- block-size: auto;
173
+ /* Center the collapse button in collapsed state */
174
+ .container.collapsed .productHeader {
175
+ justify-content: center;
176
+ gap: 0;
133
177
  }
134
178
 
135
- .collapsedIcon {
136
- transform: rotate(180deg);
137
- transition: transform 0.3s ease;
138
- }
139
- .content {
140
- overflow: auto;
141
- flex: 1 1 auto;
142
- overflow-y: visible;
143
- display: flex;
144
- flex-direction: column;
145
- position: relative;
146
- width: 100%;
147
- gap: 5px;
148
- &:not(.collapsed) {
149
- gap: var(--spacing-md);
150
- }
179
+ .container.collapsed .header {
180
+ padding: 0;
151
181
  }
152
182
 
153
- .footer {
154
- flex: 0 0 auto;
183
+ .container.collapsed .productHeader button {
184
+ margin-inline: auto;
155
185
  }
@@ -1,13 +1,26 @@
1
1
  'use client';
2
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect } from 'react';
4
+ import styles from './SidebarItems.module.css';
4
5
  import { useSidebar } from '../../providers/SidebarProvider';
5
6
  import { ExpandableSidebarItem } from '../expandable-sidebar-item/ExpandableSidebarItem';
6
7
  import { SidebarItem } from '../SidebarItem';
7
8
  export function SidebarItems({ activeLink }) {
8
- const { filteredItems, setActiveLink } = useSidebar();
9
+ const { filteredItems, setActiveLink, isSidebarCollapsed } = useSidebar();
9
10
  useEffect(() => {
10
11
  setActiveLink(activeLink !== null && activeLink !== void 0 ? activeLink : '');
11
12
  }, [activeLink, setActiveLink]);
12
- return (_jsx(_Fragment, { children: filteredItems === null || filteredItems === void 0 ? void 0 : filteredItems.map(({ component: Component, label, icon, children, href }, id) => (children === null || children === void 0 ? void 0 : children.length) ? (_jsx(ExpandableSidebarItem, { items: children, label: label, icon: icon, href: href, component: Component }, label)) : (_jsx(SidebarItem, { component: Component, label: label, icon: icon, href: href }, id))) }));
13
+ const renderItem = (item, key) => {
14
+ var _a, _b;
15
+ if (item.type === 'group') {
16
+ return isSidebarCollapsed ? ((_a = item.children) === null || _a === void 0 ? void 0 : _a.map((child, idx) => renderItem(child, `${key}-c${idx}`))) : (_jsxs("div", { className: styles.group, children: [_jsx("div", { className: styles.groupLabel, children: item.label }), (_b = item.children) === null || _b === void 0 ? void 0 : _b.map((child, idx) => renderItem(child, `${key}-c${idx}`))] }, key));
17
+ }
18
+ if (item.type === 'expandable') {
19
+ const { component: Component, label, icon, children, href } = item;
20
+ return (_jsx(ExpandableSidebarItem, { items: children, label: label, icon: icon, href: href, component: Component }, key));
21
+ }
22
+ const { component: Component, label, icon, href } = item;
23
+ return _jsx(SidebarItem, { component: Component, label: label, icon: icon, href: href }, key);
24
+ };
25
+ return filteredItems === null || filteredItems === void 0 ? void 0 : filteredItems.map((item, idx) => renderItem(item, `nav-${idx}-${item.label}`));
13
26
  }
@@ -0,0 +1,20 @@
1
+ .group {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--spacing-xxs);
5
+ margin-top: var(--spacing-xs);
6
+ }
7
+
8
+ .group:first-child {
9
+ margin-top: 0;
10
+ }
11
+
12
+ .groupLabel {
13
+ padding: 0 var(--spacing-xs);
14
+ margin: var(--spacing-xs) 0;
15
+ font-size: var(--font-size-xs);
16
+ font-weight: var(--font-weight-medium);
17
+ color: var(--color-fg-subtle);
18
+ letter-spacing: 0.04em;
19
+ text-transform: uppercase;
20
+ }
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { NavBarItem } from '../../../components/nav-bar/NavBar';
4
4
  export type SidebarContextValue = {
5
5
  defaultExpanded: boolean | null;
6
- expandedItems: Set<string | undefined>;
6
+ expandedItems: Set<string>;
7
7
  resetExpandAll: () => void;
8
8
  activeQuery: string;
9
9
  areItemsCollapsed: boolean;
@@ -13,6 +13,9 @@ export type SidebarContextValue = {
13
13
  filteredItems?: NavBarItem[];
14
14
  activeLink?: string;
15
15
  setActiveLink: (href: string) => void;
16
+ expandItem: (href: string) => void;
17
+ collapseItem: (href: string) => void;
18
+ isExpanded: (href: string) => boolean;
16
19
  isSidebarCollapsed: boolean;
17
20
  handleSidebarCollapseChange: (collapsed: boolean) => void;
18
21
  };