@servicetitan/navigation 10.6.1 → 11.0.0-canary.237.0c461af.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 (164) hide show
  1. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts.map +1 -1
  2. package/dist/components/header-navigation/header-navigation-extra.stories.js +5 -5
  3. package/dist/components/header-navigation/header-navigation-extra.stories.js.map +1 -1
  4. package/dist/components/header-navigation/header-navigation-links.d.ts.map +1 -1
  5. package/dist/components/header-navigation/header-navigation-links.js +2 -2
  6. package/dist/components/header-navigation/header-navigation-links.js.map +1 -1
  7. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts.map +1 -1
  8. package/dist/components/header-navigation/header-navigation-stacked.stories.js +1 -1
  9. package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +1 -1
  10. package/dist/components/header-navigation/header-navigation.stories.d.ts.map +1 -1
  11. package/dist/components/header-navigation/header-navigation.stories.js +2 -2
  12. package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
  13. package/dist/components/header-navigation/with-tooltip.d.ts +1 -1
  14. package/dist/components/header-navigation/with-tooltip.d.ts.map +1 -1
  15. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts.map +1 -1
  16. package/dist/components/left-navigation/header-navigation-tiny.stories.js +2 -2
  17. package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
  18. package/dist/components/left-navigation/interface.d.ts +1 -1
  19. package/dist/components/left-navigation/interface.d.ts.map +1 -1
  20. package/dist/components/left-navigation/side-navigation-links-internal.d.ts +3 -1
  21. package/dist/components/left-navigation/side-navigation-links-internal.d.ts.map +1 -1
  22. package/dist/components/left-navigation/side-navigation-links-internal.js +3 -3
  23. package/dist/components/left-navigation/side-navigation-links-internal.js.map +1 -1
  24. package/dist/components/left-navigation/side-navigation.d.ts.map +1 -1
  25. package/dist/components/left-navigation/side-navigation.js +8 -7
  26. package/dist/components/left-navigation/side-navigation.js.map +1 -1
  27. package/dist/components/left-navigation/side-navigation.module.less +21 -19
  28. package/dist/components/links.d.ts.map +1 -1
  29. package/dist/components/links.js +7 -7
  30. package/dist/components/links.js.map +1 -1
  31. package/dist/components/logo/logo-company-title.d.ts +1 -0
  32. package/dist/components/logo/logo-company-title.d.ts.map +1 -1
  33. package/dist/components/logo/logo-company-title.js +2 -2
  34. package/dist/components/logo/logo-company-title.js.map +1 -1
  35. package/dist/components/profile-dropdown/profile-dropdown.d.ts +15 -9
  36. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  37. package/dist/components/profile-dropdown/profile-dropdown.js +7 -8
  38. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  39. package/dist/components/profile-dropdown/profile-dropdown.module.less +4 -0
  40. package/dist/components/profile-dropdown/profile-dropdown.stories.js +2 -2
  41. package/dist/components/profile-dropdown/profile-dropdown.stories.js.map +1 -1
  42. package/dist/components/titan-layout/index.d.ts +6 -0
  43. package/dist/components/titan-layout/index.d.ts.map +1 -0
  44. package/dist/components/titan-layout/index.js +6 -0
  45. package/dist/components/titan-layout/index.js.map +1 -0
  46. package/dist/components/titan-layout/interface-internal.d.ts +6 -0
  47. package/dist/components/titan-layout/interface-internal.d.ts.map +1 -0
  48. package/dist/components/titan-layout/interface-internal.js +2 -0
  49. package/dist/components/titan-layout/interface-internal.js.map +1 -0
  50. package/dist/components/titan-layout/interface.d.ts +21 -0
  51. package/dist/components/titan-layout/interface.d.ts.map +1 -0
  52. package/dist/components/titan-layout/interface.js +2 -0
  53. package/dist/components/titan-layout/interface.js.map +1 -0
  54. package/dist/components/titan-layout/layout-context.d.ts +20 -0
  55. package/dist/components/titan-layout/layout-context.d.ts.map +1 -0
  56. package/dist/components/titan-layout/layout-context.js +12 -0
  57. package/dist/components/titan-layout/layout-context.js.map +1 -0
  58. package/dist/components/titan-layout/layout-header-links.d.ts +7 -0
  59. package/dist/components/titan-layout/layout-header-links.d.ts.map +1 -0
  60. package/dist/components/titan-layout/layout-header-links.js +32 -0
  61. package/dist/components/titan-layout/layout-header-links.js.map +1 -0
  62. package/dist/components/titan-layout/layout-header.d.ts +20 -0
  63. package/dist/components/titan-layout/layout-header.d.ts.map +1 -0
  64. package/dist/components/titan-layout/layout-header.js +11 -0
  65. package/dist/components/titan-layout/layout-header.js.map +1 -0
  66. package/dist/components/titan-layout/layout-header.module.less +174 -0
  67. package/dist/components/titan-layout/layout-logo.d.ts +12 -0
  68. package/dist/components/titan-layout/layout-logo.d.ts.map +1 -0
  69. package/dist/components/titan-layout/layout-logo.js +15 -0
  70. package/dist/components/titan-layout/layout-logo.js.map +1 -0
  71. package/dist/components/titan-layout/layout-logo.stories.d.ts +13 -0
  72. package/dist/components/titan-layout/layout-logo.stories.d.ts.map +1 -0
  73. package/dist/components/titan-layout/layout-logo.stories.js +17 -0
  74. package/dist/components/titan-layout/layout-logo.stories.js.map +1 -0
  75. package/dist/components/titan-layout/layout-profile.d.ts +9 -0
  76. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -0
  77. package/dist/components/titan-layout/layout-profile.js +54 -0
  78. package/dist/components/titan-layout/layout-profile.js.map +1 -0
  79. package/dist/components/titan-layout/layout-profile.stories.d.ts +13 -0
  80. package/dist/components/titan-layout/layout-profile.stories.d.ts.map +1 -0
  81. package/dist/components/titan-layout/layout-profile.stories.js +13 -0
  82. package/dist/components/titan-layout/layout-profile.stories.js.map +1 -0
  83. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +46 -0
  84. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -0
  85. package/dist/components/titan-layout/layout-sidebar-links-internal.js +61 -0
  86. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -0
  87. package/dist/components/titan-layout/layout-sidebar-links.d.ts +6 -0
  88. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -0
  89. package/dist/components/titan-layout/layout-sidebar-links.js +21 -0
  90. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -0
  91. package/dist/components/titan-layout/layout-sidebar.d.ts +17 -0
  92. package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -0
  93. package/dist/components/titan-layout/layout-sidebar.js +65 -0
  94. package/dist/components/titan-layout/layout-sidebar.js.map +1 -0
  95. package/dist/components/titan-layout/layout-sidebar.module.less +516 -0
  96. package/dist/components/titan-layout/titan-layout.d.ts +38 -0
  97. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -0
  98. package/dist/components/titan-layout/titan-layout.js +147 -0
  99. package/dist/components/titan-layout/titan-layout.js.map +1 -0
  100. package/dist/components/titan-layout/titan-layout.module.less +103 -0
  101. package/dist/components/titan-layout/titan-layout.stories.d.ts +20 -0
  102. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -0
  103. package/dist/components/titan-layout/titan-layout.stories.js +80 -0
  104. package/dist/components/titan-layout/titan-layout.stories.js.map +1 -0
  105. package/dist/components/titan-layout/with-tooltip.d.ts +4 -0
  106. package/dist/components/titan-layout/with-tooltip.d.ts.map +1 -0
  107. package/dist/components/titan-layout/with-tooltip.js +4 -0
  108. package/dist/components/titan-layout/with-tooltip.js.map +1 -0
  109. package/dist/index.d.ts +2 -1
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +2 -1
  112. package/dist/index.js.map +1 -1
  113. package/dist/test/data.d.ts.map +1 -1
  114. package/dist/test/data.js +3 -3
  115. package/dist/test/data.js.map +1 -1
  116. package/dist/utils/navigation-legacy.d.ts +3 -1
  117. package/dist/utils/navigation-legacy.d.ts.map +1 -1
  118. package/dist/utils/use-breakpoint.d.ts +7 -0
  119. package/dist/utils/use-breakpoint.d.ts.map +1 -0
  120. package/dist/utils/use-breakpoint.js +13 -0
  121. package/dist/utils/use-breakpoint.js.map +1 -0
  122. package/package.json +5 -6
  123. package/src/components/header-navigation/header-navigation-extra.stories.tsx +7 -0
  124. package/src/components/header-navigation/header-navigation-links.tsx +2 -0
  125. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +5 -1
  126. package/src/components/header-navigation/header-navigation.stories.tsx +6 -1
  127. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +8 -2
  128. package/src/components/left-navigation/interface.ts +2 -2
  129. package/src/components/left-navigation/side-navigation-links-internal.tsx +21 -6
  130. package/src/components/left-navigation/side-navigation-links.tsx +1 -1
  131. package/src/components/left-navigation/side-navigation.module.less +21 -19
  132. package/src/components/left-navigation/side-navigation.module.less.d.ts +2 -1
  133. package/src/components/left-navigation/side-navigation.tsx +15 -8
  134. package/src/components/links.tsx +33 -13
  135. package/src/components/logo/logo-company-title.tsx +8 -6
  136. package/src/components/profile-dropdown/profile-dropdown.module.less +4 -0
  137. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +4 -4
  138. package/src/components/profile-dropdown/profile-dropdown.tsx +55 -51
  139. package/src/components/titan-layout/index.ts +5 -0
  140. package/src/components/titan-layout/interface-internal.ts +6 -0
  141. package/src/components/titan-layout/interface.ts +26 -0
  142. package/src/components/titan-layout/layout-context.tsx +30 -0
  143. package/src/components/titan-layout/layout-header-links.tsx +144 -0
  144. package/src/components/titan-layout/layout-header.module.less +174 -0
  145. package/src/components/titan-layout/layout-header.module.less.d.ts +16 -0
  146. package/src/components/titan-layout/layout-header.tsx +90 -0
  147. package/src/components/titan-layout/layout-logo.stories.tsx +31 -0
  148. package/src/components/titan-layout/layout-logo.tsx +57 -0
  149. package/src/components/titan-layout/layout-profile.stories.tsx +46 -0
  150. package/src/components/titan-layout/layout-profile.tsx +132 -0
  151. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +275 -0
  152. package/src/components/titan-layout/layout-sidebar-links.tsx +59 -0
  153. package/src/components/titan-layout/layout-sidebar.module.less +516 -0
  154. package/src/components/titan-layout/layout-sidebar.module.less.d.ts +48 -0
  155. package/src/components/titan-layout/layout-sidebar.tsx +295 -0
  156. package/src/components/titan-layout/titan-layout.module.less +103 -0
  157. package/src/components/titan-layout/titan-layout.module.less.d.ts +15 -0
  158. package/src/components/titan-layout/titan-layout.stories.tsx +332 -0
  159. package/src/components/titan-layout/titan-layout.tsx +365 -0
  160. package/src/components/titan-layout/with-tooltip.tsx +16 -0
  161. package/src/index.ts +2 -1
  162. package/src/test/data.tsx +3 -2
  163. package/src/utils/navigation-legacy.ts +3 -1
  164. package/src/utils/use-breakpoint.ts +19 -0
@@ -6,6 +6,7 @@ import SvgAccountInactive from '@servicetitan/anvil2/assets/icons/st/gnav_accoun
6
6
  import { BodyText, Popover, PopoverPropsStrict } from '@servicetitan/design-system';
7
7
  import classNames from 'classnames';
8
8
  import {
9
+ ComponentPropsWithoutRef,
9
10
  FC,
10
11
  HTMLAttributeAnchorTarget,
11
12
  MouseEvent,
@@ -25,6 +26,7 @@ import {
25
26
  } from '../../utils/navigation-context';
26
27
  import { getCounterTag } from '../../utils/side-nav';
27
28
  import { CounterTag } from '../counter-tag';
29
+ import { withTooltip } from '../titan-layout/with-tooltip';
28
30
  import * as Styles from './profile-dropdown.module.less';
29
31
  import { ProfileLogo } from './profile-icon';
30
32
 
@@ -146,21 +148,28 @@ const ProfileDropdownTrigger: FC<ProfileDropdownTriggerProps> = ({
146
148
  );
147
149
  };
148
150
 
151
+ export type ProfileItemContent =
152
+ | { children: string; text?: string }
153
+ | { children: ReactNode; text: string };
154
+
149
155
  export interface ProfileDropdownSectionPropsStrict {
150
156
  children: ReactNode;
151
157
  id: string;
158
+ tooltip?: string;
152
159
  className?: string;
153
160
  onClick?(e: MouseEvent): void;
154
161
  }
155
162
 
156
- interface ProfileDropdownSectionProps extends ProfileDropdownSectionPropsStrict {
157
- [key: string]: any;
158
- }
163
+ export type ProfileDropdownSectionProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> &
164
+ ProfileDropdownSectionPropsStrict &
165
+ ProfileItemContent;
159
166
 
160
167
  export const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = ({
161
168
  children,
162
169
  className,
163
170
  id,
171
+ text,
172
+ tooltip,
164
173
  onClick,
165
174
  ...rest
166
175
  }) => {
@@ -172,16 +181,20 @@ export const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = ({
172
181
  }
173
182
  };
174
183
 
175
- return (
184
+ return withTooltip(
176
185
  <div
177
- className={classNames(Styles.dropdownSection, className)}
186
+ className={classNames(Styles.dropdownSection, className, {
187
+ 'cursor-pointer': !!onClick,
188
+ })}
178
189
  onClick={clickHandler}
179
190
  data-cy={`profile-dropdown-section-${id}`}
180
191
  data-pendo={`profile-dropdown-section-${id}`}
181
192
  {...rest}
182
193
  >
183
194
  {children}
184
- </div>
195
+ </div>,
196
+ tooltip,
197
+ 'left'
185
198
  );
186
199
  };
187
200
 
@@ -193,15 +206,15 @@ export interface ProfileDropdownLinkPropsStrict {
193
206
  className?: string;
194
207
  external?: boolean;
195
208
  target?: HTMLAttributeAnchorTarget;
196
- to?: string;
209
+ tooltip?: string;
210
+ to: string;
197
211
  tag?: CounterTagData;
198
212
  counter?: CounterTagValue;
199
- onClick?: () => void;
200
213
  }
201
214
 
202
- export interface ProfileDropdownLinkProps extends ProfileDropdownLinkPropsStrict {
203
- [key: string]: any;
204
- }
215
+ export type ProfileDropdownLinkProps = Omit<ComponentPropsWithoutRef<'a'>, 'children'> &
216
+ ProfileDropdownLinkPropsStrict &
217
+ ProfileItemContent;
205
218
 
206
219
  export const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = ({
207
220
  children,
@@ -211,17 +224,14 @@ export const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = ({
211
224
  counter,
212
225
  tag,
213
226
  target,
227
+ text,
214
228
  to,
229
+ tooltip,
215
230
  onClick,
216
231
  ...rest
217
232
  }: ProfileDropdownLinkProps) => {
218
233
  const NavigationComponent = useContext(NavigationComponentContext);
219
234
 
220
- const clickHandler = (e: MouseEvent<any>) => {
221
- e.preventDefault();
222
- onClick?.();
223
- };
224
-
225
235
  const isExternalLink = external ?? to?.startsWith('http');
226
236
 
227
237
  const tagElement = useMemo(
@@ -229,41 +239,34 @@ export const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = ({
229
239
  [counter, tag]
230
240
  );
231
241
 
232
- return isExternalLink ? (
233
- <a
234
- className={classNames(Styles.dropdownSection, Styles.dropdownLink, className)}
235
- href={to}
236
- target={target}
237
- data-cy={`profile-dropdown-link-${id}`}
238
- data-pendo={`profile-dropdown-link-${id}`}
239
- {...rest}
240
- >
241
- {children}
242
- {tagElement}
243
- </a>
244
- ) : to ? (
245
- <NavigationComponent
246
- className={classNames(Styles.dropdownSection, Styles.dropdownLink, className)}
247
- target={target}
248
- to={to}
249
- data-cy={`profile-dropdown-link-${id}`}
250
- data-pendo={`profile-dropdown-link-${id}`}
251
- {...rest}
252
- >
253
- {children}
254
- {tagElement}
255
- </NavigationComponent>
256
- ) : (
257
- <a
258
- className={classNames(Styles.dropdownSection, Styles.dropdownLink, className)}
259
- onClick={clickHandler}
260
- data-cy={`profile-dropdown-link-${id}`}
261
- data-pendo={`profile-dropdown-link-${id}`}
262
- {...rest}
263
- >
264
- {children}
265
- {tagElement}
266
- </a>
242
+ return withTooltip(
243
+ isExternalLink ? (
244
+ <a
245
+ className={classNames(Styles.dropdownSection, Styles.dropdownLink, className)}
246
+ href={to}
247
+ target={target}
248
+ data-cy={`profile-dropdown-link-${id}`}
249
+ data-pendo={`profile-dropdown-link-${id}`}
250
+ {...rest}
251
+ >
252
+ {children}
253
+ {tagElement}
254
+ </a>
255
+ ) : (
256
+ <NavigationComponent
257
+ className={classNames(Styles.dropdownSection, Styles.dropdownLink, className)}
258
+ target={target}
259
+ to={to}
260
+ data-cy={`profile-dropdown-link-${id}`}
261
+ data-pendo={`profile-dropdown-link-${id}`}
262
+ {...rest}
263
+ >
264
+ {children}
265
+ {tagElement}
266
+ </NavigationComponent>
267
+ ),
268
+ tooltip,
269
+ 'left'
267
270
  );
268
271
  };
269
272
 
@@ -291,6 +294,7 @@ export interface ProfileDropdownProps extends ProfileDropdownPropsStrict {
291
294
  export interface ProfileDropdownType extends FC<ProfileDropdownProps> {
292
295
  Divider: typeof ProfileDropdownDivider;
293
296
  Link: typeof ProfileDropdownLink;
297
+ Trigger: typeof ProfileDropdownTrigger;
294
298
  Section: typeof ProfileDropdownSection;
295
299
  }
296
300
 
@@ -0,0 +1,5 @@
1
+ export * from './titan-layout';
2
+ export * from './layout-profile';
3
+ export * from './layout-context';
4
+ export * from './layout-logo';
5
+ export * from './interface';
@@ -0,0 +1,6 @@
1
+ import { FC } from 'react';
2
+ import { NavLinkComponentProps } from '../../utils/navigation-context';
3
+
4
+ export interface NavigationComponentProps {
5
+ navigationComponent: FC<NavLinkComponentProps>;
6
+ }
@@ -0,0 +1,26 @@
1
+ import { FC, ReactElement } from 'react';
2
+ import { NavigationItemData } from '../../utils/navigation';
3
+ import { TitanLayoutSidebarContextType } from './layout-context';
4
+
5
+ export interface TitanLayoutSidebarLinkWrapperProps {
6
+ children:
7
+ | ReactElement<TitanLayoutSidebarLinkProps>
8
+ | ReactElement<TitanLayoutSidebarTriggerProps>;
9
+ context: TitanLayoutSidebarContextType;
10
+ }
11
+
12
+ export interface TitanLayoutSidebarLinkProps extends Omit<NavigationItemData, 'submenu'> {
13
+ wrapper?: FC<TitanLayoutSidebarLinkWrapperProps>;
14
+ }
15
+ export interface TitanLayoutSidebarTriggerProps
16
+ extends Omit<TitanLayoutSidebarLinkProps, 'to' | 'isActive'> {
17
+ isActive?: boolean;
18
+ wrapper?: FC<TitanLayoutSidebarLinkWrapperProps>;
19
+ onClick?: () => void;
20
+ onMobileClick?: () => void;
21
+ }
22
+
23
+ export interface TitanLayoutState {
24
+ navCollapsed: boolean;
25
+ submenuExpanded?: string;
26
+ }
@@ -0,0 +1,30 @@
1
+ import { CSSProperties, FC, createContext, useContext } from 'react';
2
+ import { DefaultNavLinkComponent, NavLinkComponentProps } from '../../utils/navigation-context';
3
+ import { TitanBreakpoint } from '../../utils/use-breakpoint';
4
+
5
+ export interface TitanLayoutSidebarContextType {
6
+ styles: {
7
+ popoverContent: CSSProperties;
8
+ };
9
+ }
10
+
11
+ export type TitanLayoutPlacement = 'top' | 'side' | 'unset';
12
+
13
+ export interface TitanLayoutContextType {
14
+ NavigationComponent: FC<NavLinkComponentProps>;
15
+ breakpoint: TitanBreakpoint;
16
+ isTitanLayout: boolean;
17
+ sidebar: TitanLayoutSidebarContextType;
18
+ }
19
+
20
+ export const LayoutContext = createContext<TitanLayoutContextType>({
21
+ NavigationComponent: DefaultNavLinkComponent,
22
+ breakpoint: { name: 'lg', isMobile: false },
23
+ isTitanLayout: false,
24
+ sidebar: { styles: { popoverContent: {} } },
25
+ });
26
+
27
+ export const useTitanLayoutContext = () => useContext(LayoutContext);
28
+
29
+ export const LayoutPlacementContext = createContext<TitanLayoutPlacement | undefined>(undefined);
30
+ export const useTitanLayoutPlacementContext = () => useContext(LayoutPlacementContext);
@@ -0,0 +1,144 @@
1
+ import { Icon, IconProps } from '@servicetitan/anvil2';
2
+ import classNames from 'classnames';
3
+ import { FC, Fragment } from 'react';
4
+ import {
5
+ HeaderNavigationLinkProps,
6
+ HeaderNavigationTriggerProps,
7
+ } from '../../utils/navigation-legacy';
8
+ import { getCounterTag } from '../../utils/side-nav';
9
+ import { CounterTag, CounterTagProps } from '../counter-tag';
10
+ // use v1 tooltips due to bug with v2 in monolith
11
+ import { withTooltip } from '../header-navigation/with-tooltip';
12
+ import { useTitanLayoutContext } from './layout-context';
13
+ import * as Styles from './layout-header.module.less';
14
+
15
+ /** Content for navigation items */
16
+ const HeaderNavigationItemContent: FC<{
17
+ tag?: CounterTagProps;
18
+ counterClassName?: string;
19
+ icon: IconProps['svg'] | undefined;
20
+ iconActive?: IconProps['svg'];
21
+ label?: string;
22
+ labelClassName?: string;
23
+ }> = ({ counterClassName, icon, iconActive, label, labelClassName, tag }) => {
24
+ return (
25
+ <Fragment>
26
+ {!!icon && <Icon svg={icon} className={Styles.navigationIcon} />}
27
+ {!!iconActive && (
28
+ <Icon
29
+ svg={iconActive}
30
+ className={classNames(Styles.navigationIcon, Styles.navigationIconActive)}
31
+ />
32
+ )}
33
+
34
+ {!!label && (
35
+ <span className={classNames(Styles.navigationItemLabel, labelClassName)}>
36
+ {label}
37
+ </span>
38
+ )}
39
+
40
+ {!!tag && (
41
+ <CounterTag
42
+ data={tag}
43
+ className={classNames(Styles.navigationItemCounter, counterClassName)}
44
+ longClassName={Styles.navigationItemCounterLong}
45
+ />
46
+ )}
47
+ </Fragment>
48
+ );
49
+ };
50
+
51
+ /** Navigation extra item with link */
52
+ export const LayoutHeaderNavigationLink: FC<HeaderNavigationLinkProps> = ({
53
+ id,
54
+ to,
55
+ hint,
56
+ tooltip,
57
+ className,
58
+ counter,
59
+ icon,
60
+ iconActive,
61
+ iconClassName,
62
+ iconComponent,
63
+ iconName,
64
+ isActive,
65
+ label,
66
+ labelClassName,
67
+ tag,
68
+ target,
69
+ ...rest
70
+ }) => {
71
+ const { NavigationComponent } = useTitanLayoutContext();
72
+
73
+ return withTooltip(
74
+ <NavigationComponent
75
+ data-cy={`navigation-link-${id}`}
76
+ data-pendo={`navigation-link-${id}`}
77
+ {...rest}
78
+ key={id}
79
+ to={to}
80
+ title={hint}
81
+ className={classNames(Styles.navigationLink, className, {
82
+ [Styles.navigationItemActive]: isActive === true,
83
+ [Styles.navigationItemIconState]: !!icon && !!iconActive,
84
+ })}
85
+ isActive={typeof isActive === 'function' ? isActive : undefined}
86
+ activeClassName={Styles.navigationItemActive}
87
+ target={target}
88
+ >
89
+ <HeaderNavigationItemContent
90
+ tag={getCounterTag(counter, tag)}
91
+ icon={icon}
92
+ iconActive={iconActive}
93
+ label={label}
94
+ labelClassName={labelClassName}
95
+ />
96
+ </NavigationComponent>,
97
+ tooltip
98
+ );
99
+ };
100
+
101
+ /** Navigation extra item with icon button */
102
+ export const LayoutHeaderNavigationTrigger: FC<HeaderNavigationTriggerProps> = ({
103
+ id,
104
+ className,
105
+ counter,
106
+ icon,
107
+ iconActive,
108
+ iconName,
109
+ isActive,
110
+ hint,
111
+ label,
112
+ labelClassName,
113
+ tag,
114
+ tooltip,
115
+ title,
116
+ titleClassName,
117
+ ...rest
118
+ }) => {
119
+ return withTooltip(
120
+ <div
121
+ data-cy={`navigation-trigger-${id}`}
122
+ data-pendo={`navigation-trigger-${id}`}
123
+ {...rest}
124
+ title={hint}
125
+ className={classNames(
126
+ Styles.navigationLink,
127
+ {
128
+ [Styles.navigationItemActive]: isActive === true,
129
+ [Styles.navigationItemIconState]: !!icon && !!iconActive,
130
+ },
131
+ 'cursor-pointer',
132
+ className
133
+ )}
134
+ >
135
+ <HeaderNavigationItemContent
136
+ tag={getCounterTag(counter, tag)}
137
+ icon={isActive && iconActive ? iconActive : icon}
138
+ label={label}
139
+ labelClassName={labelClassName}
140
+ />
141
+ </div>,
142
+ tooltip
143
+ );
144
+ };
@@ -0,0 +1,174 @@
1
+ /* stylelint-disable no-descending-specificity */
2
+ @import (reference) '@servicetitan/tokens/core/tokens.less';
3
+
4
+ @size-links-tiny: 24px;
5
+
6
+ .header {
7
+ display: flex;
8
+ justify-content: space-between;
9
+
10
+ background-color: @color-white;
11
+ color: @color-black;
12
+ border-bottom: 1px solid @color-neutral-60;
13
+
14
+ & > * {
15
+ overflow-y: hidden;
16
+ }
17
+
18
+ .he-top-left {
19
+ display: flex;
20
+ align-items: center;
21
+ }
22
+
23
+ .he-top-right {
24
+ & > * {
25
+ color: @color-black;
26
+ }
27
+
28
+ .he-top-right-text {
29
+ font-size: @typescale-2;
30
+ font-weight: @font-weight-bold;
31
+ font-family: @base-font-family;
32
+ margin-right: @spacing-1;
33
+ }
34
+ }
35
+
36
+ :global(.profile-dropdown-image) {
37
+ height: 24px;
38
+ width: 24px;
39
+ }
40
+
41
+ :global(.profile-dropdown-trigger) {
42
+ height: 32px;
43
+ font-size: @size-links-tiny;
44
+ }
45
+
46
+ .navigation-link {
47
+ border-radius: 12px;
48
+ font-size: @size-links-tiny;
49
+ color: inherit;
50
+
51
+ &.navigation-item-active:not(.navigation-item-overflow) {
52
+ background-color: @color-blue-100 !important;
53
+ color: @color-blue-500 !important;
54
+ }
55
+ &:hover:not(.navigation-item-active):not(.navigation-item-overflow) {
56
+ background-color: rgba(0, 0, 0, 0.12) !important;
57
+ }
58
+
59
+ &.navigation-item-icon-state.navigation-item-active {
60
+ .navigation-icon:not(.navigation-icon-active) {
61
+ display: none;
62
+ }
63
+
64
+ .navigation-icon.navigation-icon-active[data-anv][data-anv] {
65
+ display: block;
66
+ }
67
+ }
68
+ }
69
+
70
+ .navigation-icon[data-anv][data-anv] {
71
+ display: inline-block;
72
+ color: inherit;
73
+ height: 24px;
74
+ width: 24px;
75
+
76
+ > svg {
77
+ height: @size-links-tiny;
78
+ width: @size-links-tiny;
79
+ }
80
+
81
+ &.navigation-icon-active {
82
+ display: none;
83
+ }
84
+ }
85
+ }
86
+
87
+ // desktop
88
+ @media only screen and (min-width: 768px) {
89
+ .header {
90
+ height: var(--nav-offset-top);
91
+ .navigation-link {
92
+ margin: 6px 2px;
93
+ padding: 6px 6px;
94
+ }
95
+
96
+ .he-top-left {
97
+ padding-left: @spacing-1;
98
+ }
99
+ .he-top-center {
100
+ flex: 1;
101
+ margin-left: @spacing-2;
102
+ margin-right: @spacing-2;
103
+ max-width: 400px;
104
+ }
105
+ }
106
+ }
107
+ // desktop wide
108
+ @media only screen and (min-width: 1200px) {
109
+ .header {
110
+ display: grid;
111
+ grid-template-columns: repeat(3, 1fr);
112
+ grid-template-rows: 48px;
113
+
114
+ .he-top-left,
115
+ .he-top-center,
116
+ .he-top-right {
117
+ grid-column: span 1;
118
+ }
119
+
120
+ .he-top-center {
121
+ max-width: unset;
122
+ }
123
+ }
124
+ }
125
+
126
+ // mobile
127
+ @media only screen and (max-width: 768px) {
128
+ .header {
129
+ padding: @spacing-1 @spacing-half;
130
+
131
+ .navigation-link {
132
+ padding: 10px;
133
+ }
134
+
135
+ .he-top-center {
136
+ max-width: unset;
137
+ flex: 1;
138
+ margin-left: @spacing-3;
139
+ margin-right: @spacing-3;
140
+ }
141
+ }
142
+ }
143
+
144
+ .navigation-link {
145
+ // styles specific to extra nav links
146
+ color: @color-black;
147
+ position: relative;
148
+ display: flex;
149
+ align-items: center;
150
+ flex-wrap: nowrap;
151
+ text-wrap: nowrap;
152
+
153
+ .navigation-item-counter {
154
+ color: @color-white;
155
+ font-weight: @font-weight-semibold;
156
+ font-size: 8px !important;
157
+ min-width: 12px;
158
+ position: absolute;
159
+ top: 4px;
160
+ right: -2px;
161
+ }
162
+
163
+ .navigation-item-label {
164
+ color: inherit;
165
+ font-size: @typescale-1;
166
+ font-family: @base-font-family;
167
+ font-weight: @font-weight-semibold;
168
+ margin-left: @spacing-half;
169
+ }
170
+
171
+ &.navigation-item-counter-long {
172
+ right: -8px;
173
+ }
174
+ }
@@ -0,0 +1,16 @@
1
+ export const __esModule: true;
2
+ export const heTopCenter: string;
3
+ export const heTopLeft: string;
4
+ export const heTopRight: string;
5
+ export const heTopRightText: string;
6
+ export const header: string;
7
+ export const navigationIcon: string;
8
+ export const navigationIconActive: string;
9
+ export const navigationItemActive: string;
10
+ export const navigationItemCounter: string;
11
+ export const navigationItemCounterLong: string;
12
+ export const navigationItemIconState: string;
13
+ export const navigationItemLabel: string;
14
+ export const navigationItemOverflow: string;
15
+ export const navigationLink: string;
16
+
@@ -0,0 +1,90 @@
1
+ import SvgBurgerMenu from '@servicetitan/anvil2/assets/icons/material/round/menu.svg';
2
+ import classNames from 'classnames';
3
+ import { ComponentPropsWithoutRef, FC, ReactElement, ReactNode } from 'react';
4
+ import { LayoutPlacementContext, useTitanLayoutContext } from './layout-context';
5
+ import { LayoutHeaderNavigationTrigger } from './layout-header-links';
6
+ import * as Styles from './layout-header.module.less';
7
+ import { TitanLayoutLogoProps } from './layout-logo';
8
+
9
+ export interface TitanLayoutHeaderLogoProps {
10
+ title?: true | string;
11
+ mantleFill?: string;
12
+ to?: string;
13
+ }
14
+
15
+ export type LayoutHeaderProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> & {
16
+ right?: ReactNode;
17
+ rightText?: string;
18
+ rightClassName?: string;
19
+
20
+ id?: string;
21
+
22
+ center?: ReactElement;
23
+ centerClassName?: string;
24
+
25
+ logo: ReactElement<TitanLayoutLogoProps>;
26
+ profile?: ReactElement;
27
+
28
+ onBurgerClick?: (e: MouseEvent) => void;
29
+ };
30
+
31
+ export const LayoutHeader: FC<LayoutHeaderProps> = ({
32
+ className,
33
+ right,
34
+ rightText,
35
+ rightClassName,
36
+ center,
37
+ centerClassName,
38
+ logo,
39
+ profile,
40
+ onBurgerClick,
41
+ ...rest
42
+ }) => {
43
+ const { breakpoint } = useTitanLayoutContext();
44
+
45
+ return (
46
+ <LayoutPlacementContext.Provider value="top">
47
+ <div
48
+ className={classNames(Styles.header, className)}
49
+ {...rest}
50
+ data-cy="header-navigation"
51
+ >
52
+ <div className={classNames(Styles.heTopLeft)} data-cy="navigation-left">
53
+ {breakpoint.isMobile && (
54
+ <LayoutHeaderNavigationTrigger
55
+ id="burger"
56
+ title=""
57
+ icon={SvgBurgerMenu}
58
+ iconActive={SvgBurgerMenu}
59
+ className="m-r-1"
60
+ onClick={onBurgerClick}
61
+ />
62
+ )}
63
+ {logo}
64
+ </div>
65
+ <div
66
+ className={classNames(
67
+ Styles.heTopCenter,
68
+ 'd-f align-items-center justify-content-center',
69
+ centerClassName
70
+ )}
71
+ data-cy="navigation-center"
72
+ >
73
+ {center}
74
+ </div>
75
+ <div
76
+ className={classNames(
77
+ 'd-f flex-row justify-content-end align-items-center',
78
+ Styles.heTopRight,
79
+ rightClassName
80
+ )}
81
+ data-cy="navigation-right"
82
+ >
83
+ {!!rightText && <div className={Styles.heTopRightText}>{rightText}</div>}
84
+ {right}
85
+ {profile}
86
+ </div>
87
+ </div>
88
+ </LayoutPlacementContext.Provider>
89
+ );
90
+ };