@servicetitan/navigation 13.0.0-canary.256.b43c6d7.0 → 13.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 (116) hide show
  1. package/dist/components/counter-tag.d.ts +1 -1
  2. package/dist/components/counter-tag.d.ts.map +1 -1
  3. package/dist/components/counter-tag.js.map +1 -1
  4. package/dist/components/profile-dropdown/interface.d.ts +55 -0
  5. package/dist/components/profile-dropdown/interface.d.ts.map +1 -0
  6. package/dist/components/profile-dropdown/interface.js +3 -0
  7. package/dist/components/profile-dropdown/interface.js.map +1 -0
  8. package/dist/components/profile-dropdown/profile-dropdown-legacy.stories.d.ts +5 -1
  9. package/dist/components/profile-dropdown/profile-dropdown-legacy.stories.d.ts.map +1 -1
  10. package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.d.ts +5 -1
  11. package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.d.ts.map +1 -1
  12. package/dist/components/profile-dropdown/profile-dropdown.d.ts +9 -79
  13. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  14. package/dist/components/profile-dropdown/profile-dropdown.js +17 -14
  15. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  16. package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts +5 -1
  17. package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts.map +1 -1
  18. package/dist/components/titan-layout/interface-internal.d.ts +12 -0
  19. package/dist/components/titan-layout/interface-internal.d.ts.map +1 -1
  20. package/dist/components/titan-layout/interface-internal.js.map +1 -1
  21. package/dist/components/titan-layout/interface.d.ts +60 -4
  22. package/dist/components/titan-layout/interface.d.ts.map +1 -1
  23. package/dist/components/titan-layout/interface.js.map +1 -1
  24. package/dist/components/titan-layout/layout-header-dark.d.ts.map +1 -1
  25. package/dist/components/titan-layout/layout-header-dark.js +24 -12
  26. package/dist/components/titan-layout/layout-header-dark.js.map +1 -1
  27. package/dist/components/titan-layout/layout-header-links-internal.d.ts +22 -3
  28. package/dist/components/titan-layout/layout-header-links-internal.d.ts.map +1 -1
  29. package/dist/components/titan-layout/layout-header-links-internal.js +15 -18
  30. package/dist/components/titan-layout/layout-header-links-internal.js.map +1 -1
  31. package/dist/components/titan-layout/layout-header-links.d.ts +2 -3
  32. package/dist/components/titan-layout/layout-header-links.d.ts.map +1 -1
  33. package/dist/components/titan-layout/layout-header-links.js +25 -5
  34. package/dist/components/titan-layout/layout-header-links.js.map +1 -1
  35. package/dist/components/titan-layout/layout-header.d.ts +2 -0
  36. package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
  37. package/dist/components/titan-layout/layout-header.js +25 -16
  38. package/dist/components/titan-layout/layout-header.js.map +1 -1
  39. package/dist/components/titan-layout/layout-header.module.less +37 -1
  40. package/dist/components/titan-layout/layout-header.module.less.d.ts +3 -0
  41. package/dist/components/titan-layout/layout-profile.d.ts +8 -5
  42. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
  43. package/dist/components/titan-layout/layout-profile.js +29 -21
  44. package/dist/components/titan-layout/layout-profile.js.map +1 -1
  45. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +48 -24
  46. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
  47. package/dist/components/titan-layout/layout-sidebar-links-internal.js +62 -51
  48. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
  49. package/dist/components/titan-layout/layout-sidebar-links.d.ts +2 -2
  50. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
  51. package/dist/components/titan-layout/layout-sidebar-links.js +27 -14
  52. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
  53. package/dist/components/titan-layout/layout-sidebar.d.ts +1 -1
  54. package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
  55. package/dist/components/titan-layout/layout-sidebar.js +81 -104
  56. package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
  57. package/dist/components/titan-layout/layout-sidebar.module.less +74 -22
  58. package/dist/components/titan-layout/titan-layout-default.stories.d.ts +16 -0
  59. package/dist/components/titan-layout/titan-layout-default.stories.d.ts.map +1 -0
  60. package/dist/components/titan-layout/titan-layout-legacy.stories.d.ts +10 -0
  61. package/dist/components/titan-layout/titan-layout-legacy.stories.d.ts.map +1 -0
  62. package/dist/components/titan-layout/titan-layout-stacked.stories.d.ts +10 -0
  63. package/dist/components/titan-layout/titan-layout-stacked.stories.d.ts.map +1 -0
  64. package/dist/components/titan-layout/titan-layout.d.ts +28 -1
  65. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
  66. package/dist/components/titan-layout/titan-layout.js +30 -11
  67. package/dist/components/titan-layout/titan-layout.js.map +1 -1
  68. package/dist/index.d.ts +0 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js.map +1 -1
  71. package/dist/test/data.d.ts +0 -22
  72. package/dist/test/data.d.ts.map +1 -1
  73. package/dist/test/data.js +0 -197
  74. package/dist/test/data.js.map +1 -1
  75. package/dist/test/titan-layout.d.ts +16 -0
  76. package/dist/test/titan-layout.d.ts.map +1 -0
  77. package/dist/test/titan-layout.js +21 -0
  78. package/dist/test/titan-layout.js.map +1 -0
  79. package/dist/utils/navigation.d.ts +1 -4
  80. package/dist/utils/navigation.d.ts.map +1 -1
  81. package/dist/utils/navigation.js.map +1 -1
  82. package/package.json +4 -4
  83. package/src/components/counter-tag.tsx +1 -1
  84. package/src/components/profile-dropdown/interface.ts +47 -0
  85. package/src/components/profile-dropdown/profile-dropdown-legacy.stories.tsx +3 -3
  86. package/src/components/profile-dropdown/profile-dropdown-stacked.stories.tsx +3 -3
  87. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +39 -39
  88. package/src/components/profile-dropdown/profile-dropdown.tsx +37 -104
  89. package/src/components/titan-layout/interface-internal.ts +13 -0
  90. package/src/components/titan-layout/interface.ts +64 -7
  91. package/src/components/titan-layout/layout-header-dark.tsx +21 -5
  92. package/src/components/titan-layout/layout-header-links-internal.tsx +41 -54
  93. package/src/components/titan-layout/layout-header-links.tsx +64 -8
  94. package/src/components/titan-layout/layout-header.module.less +37 -1
  95. package/src/components/titan-layout/layout-header.module.less.d.ts +3 -0
  96. package/src/components/titan-layout/layout-header.tsx +26 -13
  97. package/src/components/titan-layout/layout-profile.tsx +51 -28
  98. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +155 -102
  99. package/src/components/titan-layout/layout-sidebar-links.tsx +45 -12
  100. package/src/components/titan-layout/layout-sidebar.module.less +74 -22
  101. package/src/components/titan-layout/layout-sidebar.tsx +55 -80
  102. package/src/components/titan-layout/{titan-layout.stories.tsx → titan-layout-default.stories.tsx} +100 -84
  103. package/src/components/titan-layout/titan-layout-legacy.stories.tsx +24 -0
  104. package/src/components/titan-layout/titan-layout-stacked.stories.tsx +30 -0
  105. package/src/components/titan-layout/titan-layout.tsx +67 -12
  106. package/src/index.ts +0 -1
  107. package/src/test/data.tsx +0 -165
  108. package/src/test/titan-layout.tsx +34 -0
  109. package/src/utils/navigation.ts +1 -6
  110. package/dist/components/titan-layout/titan-layout.stories.d.ts +0 -29
  111. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +0 -1
  112. package/dist/utils/navigation-legacy.d.ts +0 -88
  113. package/dist/utils/navigation-legacy.d.ts.map +0 -1
  114. package/dist/utils/navigation-legacy.js +0 -3
  115. package/dist/utils/navigation-legacy.js.map +0 -1
  116. package/src/utils/navigation-legacy.ts +0 -106
@@ -2,6 +2,18 @@
2
2
  /* stylelint-disable no-duplicate-selectors */
3
3
  @import (reference) '@servicetitan/tokens/core/tokens.less';
4
4
 
5
+ @keyframes ExtraPulseAnimation {
6
+ 0% {
7
+ opacity: 0.7;
8
+ }
9
+ 50% {
10
+ opacity: 0.5;
11
+ }
12
+ 100% {
13
+ opacity: 0;
14
+ }
15
+ }
16
+
5
17
  @size-links-tiny: 24px;
6
18
  @bg-light: @color-white;
7
19
  @bg-dark: @color-neutral-300;
@@ -36,6 +48,11 @@
36
48
  overflow-y: hidden;
37
49
  }
38
50
 
51
+ .he-top-left {
52
+ display: flex;
53
+ flex-direction: row;
54
+ }
55
+
39
56
  .he-top-center {
40
57
  overflow: hidden;
41
58
  }
@@ -146,7 +163,7 @@
146
163
  grid-template-columns: repeat(3, 1fr);
147
164
  grid-template-rows: 48px;
148
165
 
149
- .logo,
166
+ .he-top-left,
150
167
  .he-top-center,
151
168
  .he-top-right {
152
169
  grid-column: span 1;
@@ -352,6 +369,25 @@
352
369
  }
353
370
  }
354
371
 
372
+ .he-top-right .navigation-item-flashing {
373
+ &::before {
374
+ content: '';
375
+ position: absolute;
376
+ animation-name: ExtraPulseAnimation;
377
+ will-change: opacity;
378
+ background-color: var(--color-neutral-60, @color-neutral-60);
379
+ animation-iteration-count: infinite;
380
+ animation-duration: 500ms;
381
+ animation-direction: alternate;
382
+ border-radius: 12px;
383
+ inset: 0;
384
+ }
385
+
386
+ &.navigation-item-active::before {
387
+ background-color: var(--color-blue-200, @color-blue-200);
388
+ }
389
+ }
390
+
355
391
  // styles specific to main nav links
356
392
  .header-navigation .navigation-link {
357
393
  font-family: @base-font-family;
@@ -1,7 +1,9 @@
1
1
  export const __esModule: true;
2
2
  export const burger: string;
3
3
  export const calculating: string;
4
+ export const extraPulseAnimation: string;
4
5
  export const heTopCenter: string;
6
+ export const heTopLeft: string;
5
7
  export const heTopRight: string;
6
8
  export const heTopRightText: string;
7
9
  export const header: string;
@@ -29,6 +31,7 @@ export const navigationIconActive: string;
29
31
  export const navigationItemActive: string;
30
32
  export const navigationItemCounter: string;
31
33
  export const navigationItemCounterLong: string;
34
+ export const navigationItemFlashing: string;
32
35
  export const navigationItemIconState: string;
33
36
  export const navigationItemLabel: string;
34
37
  export const navigationLink: string;
@@ -5,6 +5,7 @@ import { LayoutPlacementContext } from './layout-context';
5
5
  import { LayoutHeaderNavigationTrigger } from './layout-header-links';
6
6
  import * as Styles from './layout-header.module.less';
7
7
  import { LayoutLogo, TitanLayoutLogoProps, isLogoCustom } from './layout-logo';
8
+ import { withTooltip } from './with-tooltip';
8
9
 
9
10
  export type LayoutHeaderProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> & {
10
11
  right?: ReactNode;
@@ -22,6 +23,8 @@ export type LayoutHeaderProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
22
23
  isMobile: boolean;
23
24
  variant: 'light' | 'dark';
24
25
  hasNotifications: boolean;
26
+ hasBurger: boolean;
27
+ burgerTooltip?: string;
25
28
  onBurgerClick?: (e: MouseEvent<never>) => void;
26
29
  };
27
30
 
@@ -37,9 +40,24 @@ export const LayoutHeader: FC<LayoutHeaderProps> = ({
37
40
  logo,
38
41
  profile,
39
42
  variant,
43
+ hasBurger,
44
+ burgerTooltip,
40
45
  onBurgerClick,
41
46
  ...rest
42
47
  }) => {
48
+ const burgerElement = hasBurger && (
49
+ <div className={Styles.burger}>
50
+ <LayoutHeaderNavigationTrigger
51
+ id="burger"
52
+ title=""
53
+ icon={SvgBurgerMenu}
54
+ iconActive={undefined}
55
+ onClick={onBurgerClick}
56
+ tag={{ value: hasNotifications }}
57
+ />
58
+ </div>
59
+ );
60
+
43
61
  return (
44
62
  <LayoutPlacementContext.Provider value="top">
45
63
  <div
@@ -53,19 +71,14 @@ export const LayoutHeader: FC<LayoutHeaderProps> = ({
53
71
  data-cy="header-navigation"
54
72
  {...rest}
55
73
  >
56
- {isMobile && (
57
- <div className={Styles.burger}>
58
- <LayoutHeaderNavigationTrigger
59
- id="burger"
60
- title=""
61
- icon={SvgBurgerMenu}
62
- iconActive={undefined}
63
- onClick={onBurgerClick}
64
- tag={{ value: hasNotifications }}
65
- />
66
- </div>
67
- )}
68
- <LayoutLogo {...logo} />
74
+ <div className={Styles.heTopLeft}>
75
+ {burgerElement &&
76
+ (burgerTooltip
77
+ ? withTooltip(burgerElement, burgerTooltip, { placement: 'bottom-end' })
78
+ : burgerElement)}
79
+ <LayoutLogo {...logo} />
80
+ </div>
81
+
69
82
  <div
70
83
  className={classNames(
71
84
  Styles.heTopCenter,
@@ -3,12 +3,13 @@ import SvgAccountInactive from '@servicetitan/anvil2/assets/icons/st/gnav_accoun
3
3
 
4
4
  import { FC, MouseEvent, useEffect, useState } from 'react';
5
5
  import { NavLinkComponentProps } from '../../utils/navigation-context';
6
+ import { getCounterTag } from '../../utils/side-nav';
6
7
  import {
7
- ProfileDropdown as DesktopProfileDropdown,
8
8
  ProfileDropdownLinkProps,
9
9
  ProfileDropdownProps,
10
10
  ProfileDropdownSectionProps,
11
- } from '../profile-dropdown/profile-dropdown';
11
+ } from '../profile-dropdown/interface';
12
+ import { DesktopProfileDropdown } from '../profile-dropdown/profile-dropdown';
12
13
  import { NavigationComponentProps } from './interface-internal';
13
14
  import { useTitanLayoutContext } from './layout-context';
14
15
  import {
@@ -23,7 +24,7 @@ export type {
23
24
  ProfileDropdownProps,
24
25
  ProfileDropdownSectionProps,
25
26
  ProfileDropdownLinkProps,
26
- } from '../profile-dropdown/profile-dropdown';
27
+ } from '../profile-dropdown/interface';
27
28
 
28
29
  const ExternalNavComponent: FC<NavLinkComponentProps> = ({
29
30
  children,
@@ -37,20 +38,27 @@ const ExternalNavComponent: FC<NavLinkComponentProps> = ({
37
38
  </a>
38
39
  );
39
40
 
40
- const ProfileDropdownContent: FC<ProfileDropdownProps> = props => {
41
+ function ProfileDropdownComponent(props: ProfileDropdownProps) {
41
42
  const { breakpoint, NavigationComponent } = useTitanLayoutContext();
42
43
  return breakpoint.isMobile ? (
43
44
  <MobileProfileDropdown {...props} navigationComponent={NavigationComponent} />
44
45
  ) : (
45
46
  <DesktopProfileDropdown {...props} />
46
47
  );
47
- };
48
- ProfileDropdownContent.displayName = 'ProfileDropdown';
48
+ }
49
49
  const profileId = '--profile';
50
50
 
51
51
  const MobileProfileDropdown: FC<ProfileDropdownProps & NavigationComponentProps> = ({
52
+ direction,
53
+ trigger,
54
+ hintPopup,
55
+ portal,
56
+ width,
57
+ onClose,
58
+ onOpen,
59
+ className,
52
60
  children,
53
- ...props
61
+ ...rest
54
62
  }) => {
55
63
  const [expanded, setExpanded] = useState(false);
56
64
  const { hasNotifications, NotificationsContextProvider } = useNotificationsState();
@@ -73,7 +81,8 @@ const MobileProfileDropdown: FC<ProfileDropdownProps & NavigationComponentProps>
73
81
  icon={SvgAccountInactive}
74
82
  iconActive={SvgAccountActive}
75
83
  isActive={expanded}
76
- {...props}
84
+ className={className}
85
+ {...rest}
77
86
  submenuExpanded={expanded}
78
87
  onExpandToggle={onExpandToggle}
79
88
  onClick={onExpandToggle}
@@ -106,71 +115,85 @@ const getText = (children: any, text: any): string | undefined => {
106
115
  return undefined;
107
116
  };
108
117
 
109
- const getTag = (
110
- tag: ProfileDropdownLinkProps['tag'],
111
- counter: ProfileDropdownLinkProps['counter']
112
- ): boolean => {
113
- return !!tag?.value || !!counter;
114
- };
115
-
116
- const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = props => {
118
+ function ProfileDropdownSection(props: ProfileDropdownSectionProps) {
117
119
  const { breakpoint } = useTitanLayoutContext();
118
120
  return breakpoint.isMobile ? (
119
121
  <MobileProfileDropdownSection {...props} />
120
122
  ) : (
121
123
  <DesktopProfileDropdown.Section {...props} />
122
124
  );
123
- };
125
+ }
124
126
  const MobileProfileDropdownSection: FC<ProfileDropdownSectionProps> = ({
127
+ id,
128
+ tooltip,
129
+ tag,
130
+ counter,
131
+
132
+ className,
125
133
  children,
126
134
  text,
127
- tooltip,
128
- title,
129
- ...props
135
+ ...rest
130
136
  }) => {
131
137
  const sectionText = getText(children, text);
132
138
  const { onNotificationsUpdate } = useNotificationsContext();
133
- onNotificationsUpdate(props.id, getTag(props.tag, props.counter));
139
+ const tagData = getCounterTag(counter, tag);
140
+ onNotificationsUpdate(id, !!tagData);
134
141
 
135
142
  return sectionText ? (
136
- <InternalSideNavigationGroupTrigger {...props} title={sectionText} />
143
+ <InternalSideNavigationGroupTrigger
144
+ {...rest}
145
+ id={id}
146
+ title={sectionText}
147
+ isActive={undefined}
148
+ tag={tagData}
149
+ className={className}
150
+ />
137
151
  ) : null;
138
152
  };
139
153
 
140
- const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = props => {
154
+ function ProfileDropdownLink(props: ProfileDropdownLinkProps) {
141
155
  const { breakpoint, NavigationComponent } = useTitanLayoutContext();
142
156
  return breakpoint.isMobile ? (
143
157
  <MobileProfileDropdownLink {...props} navigationComponent={NavigationComponent} />
144
158
  ) : (
145
159
  <DesktopProfileDropdown.Link {...props} />
146
160
  );
147
- };
161
+ }
148
162
  const MobileProfileDropdownLink: FC<ProfileDropdownLinkProps & NavigationComponentProps> = ({
163
+ id,
149
164
  external,
150
165
  to,
151
166
  tooltip,
152
167
  text,
153
168
  children,
169
+ className,
154
170
  navigationComponent,
155
- ...props
171
+ tag,
172
+ counter,
173
+ ...rest
156
174
  }) => {
157
175
  const { onNotificationsUpdate } = useNotificationsContext();
158
176
  const linkText = getText(children, text);
159
177
  const isExternalLink = external ?? to?.startsWith('http');
160
- onNotificationsUpdate(props.id, getTag(props.tag, props.counter));
178
+ const tagData = getCounterTag(counter, tag);
179
+ onNotificationsUpdate(id, !!tagData);
161
180
 
162
181
  return linkText ? (
163
182
  <InternalSideNavigationGroupLink
164
- {...props}
183
+ {...rest}
184
+ id={id}
165
185
  to={to}
166
186
  title={linkText}
187
+ isActive={undefined}
188
+ className={className}
189
+ tag={tagData}
167
190
  parentId={profileId}
168
191
  navigationComponent={isExternalLink ? ExternalNavComponent : navigationComponent}
169
192
  />
170
193
  ) : null;
171
194
  };
172
195
 
173
- export const ProfileDropdown = Object.assign(ProfileDropdownContent, {
196
+ export const ProfileDropdown = Object.assign(ProfileDropdownComponent, {
174
197
  Divider: ProfileDropdownDivider,
175
198
  Link: ProfileDropdownLink,
176
199
  Section: ProfileDropdownSection,