@servicetitan/navigation 8.2.0 → 9.0.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 (63) hide show
  1. package/dist/components/counter-tag.d.ts +2 -4
  2. package/dist/components/counter-tag.d.ts.map +1 -1
  3. package/dist/components/counter-tag.js +3 -4
  4. package/dist/components/counter-tag.js.map +1 -1
  5. package/dist/components/header-navigation/header-navigation-content.d.ts +2 -2
  6. package/dist/components/header-navigation/header-navigation-content.d.ts.map +1 -1
  7. package/dist/components/header-navigation/header-navigation-content.js +4 -4
  8. package/dist/components/header-navigation/header-navigation-content.js.map +1 -1
  9. package/dist/components/header-navigation/header-navigation-extra.stories.js +3 -3
  10. package/dist/components/header-navigation/header-navigation-extra.stories.js.map +1 -1
  11. package/dist/components/header-navigation/header-navigation-links.d.ts.map +1 -1
  12. package/dist/components/header-navigation/header-navigation-links.js +4 -4
  13. package/dist/components/header-navigation/header-navigation-links.js.map +1 -1
  14. package/dist/components/header-navigation/header-navigation-stacked.stories.js +1 -1
  15. package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +1 -1
  16. package/dist/components/header-navigation/header-navigation.module.less +2 -1
  17. package/dist/components/header-navigation/header-navigation.stories.js +1 -1
  18. package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
  19. package/dist/components/layout.stories.d.ts.map +1 -1
  20. package/dist/components/layout.stories.js +2 -1
  21. package/dist/components/layout.stories.js.map +1 -1
  22. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts +1 -1
  23. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts.map +1 -1
  24. package/dist/components/left-navigation/header-navigation-tiny-links.js +6 -6
  25. package/dist/components/left-navigation/header-navigation-tiny-links.js.map +1 -1
  26. package/dist/components/left-navigation/header-navigation-tiny.stories.js +2 -2
  27. package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
  28. package/dist/components/left-navigation/side-navigation.d.ts +8 -4
  29. package/dist/components/left-navigation/side-navigation.d.ts.map +1 -1
  30. package/dist/components/left-navigation/side-navigation.js +33 -20
  31. package/dist/components/left-navigation/side-navigation.js.map +1 -1
  32. package/dist/components/left-navigation/side-navigation.module.less +25 -13
  33. package/dist/components/left-navigation/side-navigation.stories.d.ts.map +1 -1
  34. package/dist/components/left-navigation/side-navigation.stories.js +6 -5
  35. package/dist/components/left-navigation/side-navigation.stories.js.map +1 -1
  36. package/dist/components/profile-dropdown/profile-dropdown.d.ts +1 -1
  37. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  38. package/dist/components/profile-dropdown/profile-dropdown.js +3 -3
  39. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  40. package/dist/test/data.d.ts +1 -0
  41. package/dist/test/data.d.ts.map +1 -1
  42. package/dist/test/data.js +23 -7
  43. package/dist/test/data.js.map +1 -1
  44. package/dist/utils/navigation.d.ts +9 -5
  45. package/dist/utils/navigation.d.ts.map +1 -1
  46. package/package.json +4 -4
  47. package/src/components/counter-tag.tsx +12 -9
  48. package/src/components/header-navigation/header-navigation-content.tsx +7 -7
  49. package/src/components/header-navigation/header-navigation-extra.stories.tsx +3 -3
  50. package/src/components/header-navigation/header-navigation-links.tsx +6 -4
  51. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +2 -2
  52. package/src/components/header-navigation/header-navigation.module.less +2 -1
  53. package/src/components/header-navigation/header-navigation.stories.tsx +2 -2
  54. package/src/components/layout.stories.tsx +5 -2
  55. package/src/components/left-navigation/header-navigation-tiny-links.tsx +8 -8
  56. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +3 -3
  57. package/src/components/left-navigation/side-navigation.module.less +25 -13
  58. package/src/components/left-navigation/side-navigation.module.less.d.ts +2 -0
  59. package/src/components/left-navigation/side-navigation.stories.tsx +10 -7
  60. package/src/components/left-navigation/side-navigation.tsx +71 -42
  61. package/src/components/profile-dropdown/profile-dropdown.tsx +6 -9
  62. package/src/test/data.tsx +27 -11
  63. package/src/utils/navigation.ts +10 -5
@@ -12,14 +12,16 @@ export const HeaderNavigationLink: FC<HeaderNavigationLinkProps> = ({
12
12
  to,
13
13
  hint,
14
14
  tooltip,
15
- counter,
16
15
  className,
16
+ icon,
17
+ iconActive,
17
18
  iconClassName,
18
19
  iconComponent,
19
20
  iconName,
20
21
  isActive,
21
22
  label,
22
23
  labelClassName,
24
+ tag,
23
25
  target,
24
26
  ...rest
25
27
  }) => {
@@ -41,7 +43,7 @@ export const HeaderNavigationLink: FC<HeaderNavigationLinkProps> = ({
41
43
  target={target}
42
44
  >
43
45
  <HeaderNavigationItemContent
44
- counter={counter}
46
+ tag={tag}
45
47
  iconComponent={iconComponent}
46
48
  iconClassName={iconClassName}
47
49
  iconName={iconName}
@@ -57,7 +59,6 @@ export const HeaderNavigationLink: FC<HeaderNavigationLinkProps> = ({
57
59
  export const HeaderNavigationTrigger: FC<HeaderNavigationTriggerProps> = ({
58
60
  id,
59
61
  className,
60
- counter,
61
62
  iconClassName,
62
63
  iconComponent,
63
64
  iconName,
@@ -65,6 +66,7 @@ export const HeaderNavigationTrigger: FC<HeaderNavigationTriggerProps> = ({
65
66
  label,
66
67
  labelClassName,
67
68
  hint,
69
+ tag,
68
70
  tooltip,
69
71
  ...rest
70
72
  }) => {
@@ -85,7 +87,7 @@ export const HeaderNavigationTrigger: FC<HeaderNavigationTriggerProps> = ({
85
87
  )}
86
88
  >
87
89
  <HeaderNavigationItemContent
88
- counter={counter}
90
+ tag={tag}
89
91
  iconComponent={iconComponent}
90
92
  iconClassName={iconClassName}
91
93
  iconName={iconName}
@@ -96,7 +96,7 @@ export const WithAllMonolithData = () => (
96
96
  <HeaderNavigationTrigger
97
97
  id="dialpad"
98
98
  iconName="phone"
99
- counter={2}
99
+ tag={2}
100
100
  icon={SvgIcon}
101
101
  iconActive={SvgIcon}
102
102
  />
@@ -122,7 +122,7 @@ export const WithAllMonolithData = () => (
122
122
  />
123
123
 
124
124
  <ProfileDropdown>
125
- <ProfileDropdown.Link id="tasks" to="https://googgle.com" counter={10}>
125
+ <ProfileDropdown.Link id="tasks" to="https://googgle.com" tag={10}>
126
126
  Task Management
127
127
  </ProfileDropdown.Link>
128
128
  <ProfileDropdown.Divider />
@@ -219,7 +219,8 @@
219
219
  .navigation-item-counter {
220
220
  color: @color-white;
221
221
  font-weight: @font-weight-semibold;
222
- min-width: 12px;
222
+ min-width: 12px !important;
223
+ min-height: 12px !important;
223
224
  }
224
225
 
225
226
  &:not(.navigation-item-overflow) .navigation-item-counter {
@@ -108,7 +108,7 @@ export const WithAllMonolithData = () => (
108
108
  <HeaderNavigationTrigger
109
109
  id="dialpad"
110
110
  iconName="phone"
111
- counter={2}
111
+ tag={2}
112
112
  icon={SvgIcon}
113
113
  iconActive={SvgIcon}
114
114
  />
@@ -145,7 +145,7 @@ export const WithAllMonolithData = () => (
145
145
  />
146
146
 
147
147
  <ProfileDropdown>
148
- <ProfileDropdown.Link id="tasks" to="https://googgle.com" counter={10}>
148
+ <ProfileDropdown.Link id="tasks" to="https://googgle.com" tag={10}>
149
149
  Task Management
150
150
  </ProfileDropdown.Link>
151
151
  <ProfileDropdown.Divider />
@@ -1,3 +1,4 @@
1
+ import { Page, Sidebar } from '@servicetitan/design-system';
1
2
  import { LocationInfo, withAnvil, withMemoryRouter } from '../test/data';
2
3
  import {
3
4
  WithAllMonolithData,
@@ -57,8 +58,10 @@ export const LeftNavLayoutSubmenu = () => {
57
58
  <WithAllMonolithDataCommercial />
58
59
  <div className="flex-grow-1 flex-basis-0 d-f">
59
60
  <SideNavigationWithSubmenu />
60
- <div className="flex-grow-1 flex-basis-0 p-5">
61
- <LocationInfo />
61
+ <div className="flex-grow-1 flex-basis-0">
62
+ <Page sidebar={<Sidebar localStorageKey="undefined">sidebar</Sidebar>}>
63
+ <LocationInfo />
64
+ </Page>
62
65
  </div>
63
66
  </div>
64
67
  </div>
@@ -9,13 +9,13 @@ import { withTooltip } from './with-tooltip';
9
9
 
10
10
  /** Content for navigation items */
11
11
  export const HeaderNavigationItemContent: FC<{
12
- counter?: CounterTagPropsType;
12
+ tag?: CounterTagPropsType;
13
13
  counterClassName?: string;
14
14
  icon: IconProps['svg'] | undefined;
15
15
  iconActive: IconProps['svg'] | undefined;
16
16
  label?: string;
17
17
  labelClassName?: string;
18
- }> = ({ counter, counterClassName, icon, iconActive, label, labelClassName }) => {
18
+ }> = ({ counterClassName, icon, iconActive, label, labelClassName, tag }) => {
19
19
  return (
20
20
  <Fragment>
21
21
  {!!icon && <Icon svg={icon} className={Styles.navigationIcon} />}
@@ -32,9 +32,9 @@ export const HeaderNavigationItemContent: FC<{
32
32
  </span>
33
33
  )}
34
34
 
35
- {!!counter && (
35
+ {!!tag && (
36
36
  <CounterTag
37
- data={counter}
37
+ data={tag}
38
38
  className={classNames(Styles.navigationItemCounter, counterClassName)}
39
39
  longClassName={Styles.navigationItemCounterLong}
40
40
  />
@@ -49,13 +49,13 @@ export const HeaderNavigationLink: FC<HeaderNavigationLinkProps> = ({
49
49
  to,
50
50
  hint,
51
51
  tooltip,
52
- counter,
53
52
  className,
54
53
  icon,
55
54
  iconActive,
56
55
  isActive,
57
56
  label,
58
57
  labelClassName,
58
+ tag,
59
59
  target,
60
60
  ...rest
61
61
  }) => {
@@ -78,7 +78,7 @@ export const HeaderNavigationLink: FC<HeaderNavigationLinkProps> = ({
78
78
  target={target}
79
79
  >
80
80
  <HeaderNavigationItemContent
81
- counter={counter}
81
+ tag={tag}
82
82
  icon={icon}
83
83
  iconActive={iconActive}
84
84
  label={label}
@@ -93,13 +93,13 @@ export const HeaderNavigationLink: FC<HeaderNavigationLinkProps> = ({
93
93
  export const HeaderNavigationTrigger: FC<HeaderNavigationTriggerProps> = ({
94
94
  id,
95
95
  className,
96
- counter,
97
96
  icon,
98
97
  iconActive,
99
98
  isActive,
100
99
  hint,
101
100
  label,
102
101
  labelClassName,
102
+ tag,
103
103
  tooltip,
104
104
  title,
105
105
  titleClassName,
@@ -122,7 +122,7 @@ export const HeaderNavigationTrigger: FC<HeaderNavigationTriggerProps> = ({
122
122
  )}
123
123
  >
124
124
  <HeaderNavigationItemContent
125
- counter={counter}
125
+ tag={tag}
126
126
  icon={icon}
127
127
  iconActive={iconActive}
128
128
  label={label}
@@ -86,7 +86,7 @@ export const WithAllMonolithData = () => (
86
86
  />
87
87
 
88
88
  <ProfileDropdown>
89
- <ProfileDropdown.Link id="tasks" to="https://googgle.com" counter={10}>
89
+ <ProfileDropdown.Link id="tasks" to="https://googgle.com" tag={10}>
90
90
  Task Management
91
91
  </ProfileDropdown.Link>
92
92
  <ProfileDropdown.Divider />
@@ -107,7 +107,7 @@ export const WithAllMonolithData = () => (
107
107
 
108
108
  export const WithAllMonolithDataCommercial = () => (
109
109
  <HeaderNavigationTiny
110
- className="border-bottom"
110
+ className="border-bottom z-global-nav"
111
111
  left={
112
112
  <Flex alignItems="center">
113
113
  <LogoTitan mantleFill="#2270EE" className="p-x-half" size={48} />
@@ -152,7 +152,7 @@ export const WithAllMonolithDataCommercial = () => (
152
152
  />
153
153
 
154
154
  <ProfileDropdown>
155
- <ProfileDropdown.Link id="tasks" to="https://googgle.com" counter={10}>
155
+ <ProfileDropdown.Link id="tasks" to="https://googgle.com" tag={10}>
156
156
  Task Management
157
157
  </ProfileDropdown.Link>
158
158
  <ProfileDropdown.Divider />
@@ -4,7 +4,7 @@
4
4
  @text-color: var(--colorsTextInverted, @color-white);
5
5
  @text-color-active: var(--colorsTextPrimarySubdued, @color-blue-300);
6
6
  @border-color: var(--colorsTextOnGrey, @color-neutral-200);
7
- @bg-color: var(--colorsSurfaceInvertedStrong, @color-neutral-400);
7
+ @bg-color: #0f1d26;
8
8
  @bg-color-hover: rgba(255, 255, 255, 0.08);
9
9
  @bg-color-active: rgba(120, 187, 250, 0.2);
10
10
 
@@ -51,6 +51,10 @@
51
51
  margin: 2px @spacing-half @spacing-0;
52
52
  text-align: center;
53
53
  }
54
+
55
+ .navigation-item-text.navigation-item-text-small {
56
+ font-size: 10.5px;
57
+ }
54
58
  }
55
59
 
56
60
  .options-item {
@@ -69,7 +73,6 @@
69
73
 
70
74
  .navigation-item {
71
75
  flex-direction: row;
72
- margin-bottom: @spacing-half;
73
76
  margin-left: @spacing-1;
74
77
  margin-right: @spacing-1;
75
78
 
@@ -81,9 +84,13 @@
81
84
  .navigation-item-text {
82
85
  font-family: @base-font-family;
83
86
  font-size: @typescale-3;
84
- padding-left: @spacing-2;
87
+ padding-left: @spacing-1;
85
88
  flex: 1;
86
89
  }
90
+
91
+ .navigation-item-counter {
92
+ margin-right: @spacing-1;
93
+ }
87
94
  }
88
95
 
89
96
  .options-item {
@@ -185,6 +192,8 @@
185
192
  .navigation-item-counter {
186
193
  color: @color-white;
187
194
  font-weight: @font-weight-semibold;
195
+ min-width: 12px !important;
196
+ min-height: 12px !important;
188
197
  }
189
198
 
190
199
  .navigation-item-group-toggle[data-anv][data-anv] {
@@ -211,16 +220,6 @@
211
220
  margin-bottom: @spacing-1;
212
221
  position: relative;
213
222
 
214
- &:before {
215
- content: '';
216
- position: absolute;
217
- border-left: 1px solid @color-neutral-100;
218
- width: 1px;
219
- top: @spacing-2;
220
- bottom: @spacing-1;
221
- left: 0;
222
- }
223
-
224
223
  .submenu-group-header[data-anv][data-anv] {
225
224
  padding-top: @spacing-2;
226
225
  padding-bottom: @spacing-half;
@@ -301,12 +300,25 @@
301
300
  color: @text-color;
302
301
  font-size: @typescale-2;
303
302
  border-radius: @border-radius-2;
303
+ display: flex;
304
+ flex-direction: row;
305
+ justify-content: space-between;
306
+ align-items: center;
304
307
  }
305
308
 
306
309
  .submenu-link-active {
307
310
  color: @text-color-active;
308
311
  }
309
312
 
313
+ .submenu-link-counter {
314
+ min-height: 19px !important;
315
+ min-width: 19px !important;
316
+
317
+ > span:first-child {
318
+ color: @color-black;
319
+ }
320
+ }
321
+
310
322
  .submenu-link:hover:not(.submenu-link-active) {
311
323
  background-color: @bg-color-hover;
312
324
  }
@@ -10,6 +10,7 @@ export const navigationItemGroupToggle: string;
10
10
  export const navigationItemIconSwitch: string;
11
11
  export const navigationItemIconWrapper: string;
12
12
  export const navigationItemText: string;
13
+ export const navigationItemTextSmall: string;
13
14
  export const optionsIcon: string;
14
15
  export const optionsIconWrapper: string;
15
16
  export const optionsItem: string;
@@ -24,5 +25,6 @@ export const submenu: string;
24
25
  export const submenuGroupHeader: string;
25
26
  export const submenuLink: string;
26
27
  export const submenuLinkActive: string;
28
+ export const submenuLinkCounter: string;
27
29
  export const submenuPopover: string;
28
30
 
@@ -1,13 +1,16 @@
1
+ import { Page, Sidebar } from '@servicetitan/design-system';
1
2
  import { ComponentType, useState } from 'react';
2
3
  import { LocationInfo, items, withAnvil, withMemoryRouter } from '../../test/data';
3
- import { SideNavigation } from './';
4
+ import { SideNavigation, SideNavigationExpandedState } from './';
4
5
 
5
6
  const layout = (Story: ComponentType) => {
6
7
  return (
7
8
  <div className="d-f border" style={{ height: '800px' }}>
8
9
  <Story />
9
- <div className="flex-grow-1 flex-basis-0 p-5">
10
- <LocationInfo />
10
+ <div className="flex-grow-1 flex-basis-0">
11
+ <Page sidebar={<Sidebar localStorageKey="undefined">qq</Sidebar>}>
12
+ <LocationInfo />
13
+ </Page>
11
14
  </div>
12
15
  </div>
13
16
  );
@@ -20,7 +23,7 @@ export default {
20
23
  };
21
24
 
22
25
  export const DefaultSideNavigation = () => {
23
- const [expanded, setExpanded] = useState(false);
26
+ const [expanded, setExpanded] = useState<SideNavigationExpandedState | undefined>(undefined);
24
27
  return (
25
28
  <SideNavigation
26
29
  expanded={expanded}
@@ -47,7 +50,7 @@ export const DefaultSideNavigation = () => {
47
50
  };
48
51
 
49
52
  export const SideNavigationLinksOnly = () => {
50
- const [expanded, setExpanded] = useState(false);
53
+ const [expanded, setExpanded] = useState<SideNavigationExpandedState | undefined>(undefined);
51
54
  return (
52
55
  <SideNavigation
53
56
  expanded={expanded}
@@ -73,7 +76,7 @@ export const SideNavigationLinksOnly = () => {
73
76
  };
74
77
 
75
78
  export const SideNavigationWithSubmenu = () => {
76
- const [expanded, setExpanded] = useState(false);
79
+ const [expanded, setExpanded] = useState<SideNavigationExpandedState | undefined>(undefined);
77
80
  return (
78
81
  <SideNavigation
79
82
  expanded={expanded}
@@ -87,7 +90,7 @@ export const SideNavigationWithSubmenu = () => {
87
90
  items.accountingWithSubmenu,
88
91
  items.purchasingWithSubmenu,
89
92
 
90
- items.followUps,
93
+ items.followUpsWithSubmenu,
91
94
  items.reports,
92
95
  items.marketing,
93
96
  items.priceBook,
@@ -14,12 +14,11 @@ import {
14
14
  ReactElement,
15
15
  useCallback,
16
16
  useContext,
17
- useState,
18
17
  } from 'react';
19
18
  import {
20
19
  HeaderNavigationItemData,
21
- HeaderNavigationItemLinkProps,
22
20
  HeaderNavigationItemSubmenu,
21
+ HeaderNavigationItemSubmenuLink,
23
22
  NavLinkComponentProps,
24
23
  } from '../../utils/navigation';
25
24
  import { NavigationComponentContext } from '../../utils/navigation-context';
@@ -27,6 +26,11 @@ import { CounterTag } from '../counter-tag';
27
26
  import * as Styles from './side-navigation.module.less';
28
27
  import { withTooltip } from './with-tooltip';
29
28
 
29
+ export interface SideNavigationExpandedState {
30
+ bar: boolean;
31
+ submenus?: string[];
32
+ }
33
+
30
34
  export interface SideNavigationProps {
31
35
  /** container class name */
32
36
  className?: string;
@@ -37,9 +41,9 @@ export interface SideNavigationProps {
37
41
  /** top navigation items */
38
42
  itemsTop?: HeaderNavigationItemData[];
39
43
  /** is menu expanded */
40
- expanded?: boolean;
44
+ expanded?: SideNavigationExpandedState;
41
45
  /** expand change handler */
42
- onExpandedChange(expanded: boolean): void;
46
+ onExpandedChange?(expanded: SideNavigationExpandedState): void;
43
47
  }
44
48
 
45
49
  export const SideNavigation: FC<SideNavigationProps> = ({
@@ -55,7 +59,7 @@ export const SideNavigation: FC<SideNavigationProps> = ({
55
59
  <div
56
60
  className={classNames(
57
61
  Styles.sideNav,
58
- expanded ? Styles.sideNavExpanded : Styles.sideNavSlim,
62
+ expanded?.bar ? Styles.sideNavExpanded : Styles.sideNavSlim,
59
63
  className
60
64
  )}
61
65
  id={id}
@@ -82,6 +86,7 @@ export const SideNavigation: FC<SideNavigationProps> = ({
82
86
  <SideNavigationGroupItem
83
87
  key={item.id}
84
88
  expanded={expanded}
89
+ onExpandedChange={onExpandedChange}
85
90
  navigationComponent={NavigationComponent}
86
91
  {...item}
87
92
  />
@@ -111,18 +116,14 @@ interface NavigationComponentProps {
111
116
  }
112
117
 
113
118
  interface SideNavigationItemProps extends HeaderNavigationItemData, NavigationComponentProps {
114
- expanded?: boolean;
115
- submenuExpanded?: boolean;
119
+ expanded?: SideNavigationExpandedState;
116
120
  }
117
121
 
118
122
  /** Side Navigation menu item */
119
123
  const SideNavigationItem: FC<SideNavigationItemProps> = ({
120
124
  id,
121
- submenuExpanded,
122
125
  to,
123
126
  title,
124
- hint,
125
- counter,
126
127
  className,
127
128
  iconClassName,
128
129
  iconComponent: IconComponent,
@@ -130,10 +131,12 @@ const SideNavigationItem: FC<SideNavigationItemProps> = ({
130
131
  iconActive,
131
132
  isActive,
132
133
  navigationComponent: NavigationComponent,
134
+ tag,
133
135
  expanded,
136
+ submenu,
134
137
  }) => {
135
138
  const iconSwitch = !!icon && !!iconActive && !IconComponent;
136
- const hasSubmenu = submenuExpanded === true || submenuExpanded === false;
139
+ const hasSubmenu = !!submenu;
137
140
 
138
141
  return (
139
142
  <NavigationComponent
@@ -141,7 +144,6 @@ const SideNavigationItem: FC<SideNavigationItemProps> = ({
141
144
  data-pendo={`navigation-item-${id}`}
142
145
  key={id}
143
146
  to={to}
144
- title={hint}
145
147
  className={classNames(Styles.navigationItem, className, {
146
148
  [Styles.navigationItemActive]: isActive === true,
147
149
  [Styles.navigationItemIconSwitch]: iconSwitch,
@@ -179,46 +181,68 @@ const SideNavigationItem: FC<SideNavigationItemProps> = ({
179
181
  </Fragment>
180
182
  )}
181
183
 
182
- {!!expanded && <div className={Styles.navigationItemText}>{title}</div>}
183
- {!!counter && (
184
- <CounterTag data={counter} className={Styles.navigationItemCounter} />
185
- )}
186
- {hasSubmenu && !!expanded && (
184
+ {!!expanded?.bar && <div className={Styles.navigationItemText}>{title}</div>}
185
+ {!!tag && <CounterTag data={tag} className={Styles.navigationItemCounter} />}
186
+ {hasSubmenu && !!expanded?.bar && (
187
187
  <Icon
188
- svg={submenuExpanded ? SvgGroupCollapse : SvgGroupExpand}
188
+ svg={expanded?.submenus?.includes(id) ? SvgGroupCollapse : SvgGroupExpand}
189
189
  className={Styles.navigationItemGroupToggle}
190
190
  />
191
191
  )}
192
192
  </div>
193
193
 
194
- {!expanded && <div className={Styles.navigationItemText}>{title}</div>}
194
+ {!expanded?.bar && (
195
+ <div
196
+ className={classNames(Styles.navigationItemText, {
197
+ [Styles.navigationItemTextSmall]: title.length >= 10,
198
+ })}
199
+ >
200
+ {title}
201
+ </div>
202
+ )}
195
203
  </NavigationComponent>
196
204
  );
197
205
  };
198
206
 
199
207
  const submenuPopoverStyles = { '--background-color-strong': '#24323C' } as CSSProperties;
208
+ const getFirstSubmenuLinkTo = (
209
+ submenu: HeaderNavigationItemSubmenu | undefined,
210
+ defaultTo: string
211
+ ) => submenu?.groups[0]?.links?.[0].to ?? defaultTo;
200
212
 
201
213
  /** Side Navigation menu item */
202
- const SideNavigationGroupItem: FC<SideNavigationItemProps> = ({ ...props }) => {
203
- const [submenuExpanded, setSubmenuExpanded] = useState(false);
214
+ const SideNavigationGroupItem: FC<
215
+ SideNavigationItemProps & {
216
+ onExpandedChange: undefined | ((expanded: SideNavigationExpandedState) => void);
217
+ }
218
+ > = ({ onExpandedChange, ...props }) => {
204
219
  const triggerClick = useCallback(
205
220
  (e: MouseEvent<HTMLDivElement>) => {
206
221
  e.stopPropagation();
207
222
  e.preventDefault();
208
223
 
209
- if (props.expanded) {
210
- setSubmenuExpanded(exp => !exp);
211
- }
224
+ const isSubmenuExpanded = props.expanded?.submenus?.includes(props.id);
225
+ onExpandedChange?.({
226
+ bar: !!props.expanded?.bar,
227
+ submenus: [
228
+ ...(props.expanded?.submenus?.filter(id => id !== props.id) ?? []),
229
+ ...(isSubmenuExpanded ? [] : [props.id]),
230
+ ],
231
+ });
212
232
  },
213
- [props.expanded]
233
+ [props.id, props.expanded, onExpandedChange]
214
234
  );
215
235
 
216
- return props.expanded ? (
236
+ const tag = props.submenu?.groups.some(group => group.links.some(link => !!link.tag))
237
+ ? true
238
+ : props.tag;
239
+
240
+ return props.expanded?.bar ? (
217
241
  <Fragment>
218
242
  <div onClickCapture={triggerClick}>
219
- <SideNavigationItem {...props} submenuExpanded={submenuExpanded} />
243
+ <SideNavigationItem {...props} tag={tag} />
220
244
  </div>
221
- <Collapsible open={submenuExpanded} animate>
245
+ <Collapsible open={props.expanded?.submenus?.includes(props.id)} animate>
222
246
  <div className={Styles.submenu}>
223
247
  <SideNavigationGroupContent
224
248
  groups={props.submenu?.groups ?? []}
@@ -231,12 +255,16 @@ const SideNavigationGroupItem: FC<SideNavigationItemProps> = ({ ...props }) => {
231
255
  <Popover placement="right-start" openOnHover>
232
256
  <Popover.Trigger>
233
257
  {(triggerProps: PopoverTriggerProps) => (
234
- <div {...triggerProps} onClickCapture={triggerClick}>
235
- <SideNavigationItem {...props} />
258
+ <div {...triggerProps}>
259
+ <SideNavigationItem
260
+ {...props}
261
+ to={getFirstSubmenuLinkTo(props.submenu, props.to)}
262
+ tag={tag}
263
+ />
236
264
  </div>
237
265
  )}
238
266
  </Popover.Trigger>
239
- <Popover.Content style={submenuPopoverStyles}>
267
+ <Popover.Content style={submenuPopoverStyles} className="z-global-nav-i">
240
268
  <div className={Styles.submenuPopover}>
241
269
  <Headline size="small" className="c-white m-b-half-i m-t-1">
242
270
  {props.title}
@@ -256,17 +284,14 @@ const SideNavigationGroupContent: FC<HeaderNavigationItemSubmenu & NavigationCom
256
284
  }) => {
257
285
  return (
258
286
  <Fragment>
259
- {groups.reduce((out, group) => {
287
+ {groups.reduce((out, group, index) => {
260
288
  if (!group.links.length) {
261
289
  return out;
262
290
  }
263
291
 
292
+ const key = `:group:${index}:title`;
264
293
  out.push(
265
- <Text
266
- key=":group:title"
267
- variant="eyebrow"
268
- className={Styles.submenuGroupHeader}
269
- >
294
+ <Text key={key} variant="eyebrow" className={Styles.submenuGroupHeader}>
270
295
  {group.title}
271
296
  </Text>
272
297
  );
@@ -285,8 +310,9 @@ const SideNavigationGroupContent: FC<HeaderNavigationItemSubmenu & NavigationCom
285
310
  </Fragment>
286
311
  );
287
312
  };
288
- const SideNavigationGroupLink: FC<HeaderNavigationItemLinkProps & NavigationComponentProps> = ({
313
+ const SideNavigationGroupLink: FC<HeaderNavigationItemSubmenuLink & NavigationComponentProps> = ({
289
314
  id,
315
+ tag,
290
316
  title,
291
317
  to,
292
318
  isActive,
@@ -304,22 +330,25 @@ const SideNavigationGroupLink: FC<HeaderNavigationItemLinkProps & NavigationComp
304
330
  isActive={typeof isActive === 'function' ? isActive : undefined}
305
331
  activeClassName={Styles.submenuLinkActive}
306
332
  >
307
- {title}
333
+ <span>{title}</span>
334
+ {!!tag && <CounterTag data={tag} className={Styles.submenuLinkCounter} />}
308
335
  </NavigationComponent>
309
336
  );
310
337
  };
311
338
 
312
339
  /** Side Navigation options toggle */
313
340
  export const SideNavigationOptionsToggle: FC<{
314
- expanded?: boolean;
315
- onExpandedChange(expanded: boolean): void;
341
+ expanded?: SideNavigationExpandedState;
342
+ onExpandedChange?(expanded: SideNavigationExpandedState): void;
316
343
  }> = ({ expanded, onExpandedChange }) =>
317
344
  withTooltip(
318
345
  <div
319
346
  data-cy="navigation-left-options"
320
347
  data-pendo="navigation-left-options"
321
348
  className={classNames(Styles.optionsItem)}
322
- onClick={() => onExpandedChange(!expanded)}
349
+ onClick={() =>
350
+ onExpandedChange?.({ bar: !expanded?.bar, submenus: expanded?.submenus })
351
+ }
323
352
  >
324
353
  <div className={Styles.optionsIconWrapper}>
325
354
  <Icon className={Styles.optionsIcon} svg={expanded ? SvgCollapse : SvgExpand} />