@servicetitan/navigation 12.0.2 → 13.0.0-canary.256.b43c6d7.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 (201) hide show
  1. package/dist/components/profile-dropdown/{profile-dropdown-tiny.stories.d.ts → profile-dropdown-legacy.stories.d.ts} +1 -1
  2. package/dist/components/profile-dropdown/profile-dropdown-legacy.stories.d.ts.map +1 -0
  3. package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.d.ts.map +1 -1
  4. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  5. package/dist/components/profile-dropdown/profile-dropdown.js +5 -8
  6. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  7. package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts.map +1 -1
  8. package/dist/components/titan-layout/interface.d.ts +14 -12
  9. package/dist/components/titan-layout/interface.d.ts.map +1 -1
  10. package/dist/components/titan-layout/interface.js.map +1 -1
  11. package/dist/components/titan-layout/layout-header-dark.js +1 -1
  12. package/dist/components/titan-layout/layout-header-dark.js.map +1 -1
  13. package/dist/components/titan-layout/layout-header-links.d.ts +3 -3
  14. package/dist/components/titan-layout/layout-header-links.d.ts.map +1 -1
  15. package/dist/components/titan-layout/layout-header-links.js.map +1 -1
  16. package/dist/components/titan-layout/layout-header.d.ts +2 -2
  17. package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
  18. package/dist/components/titan-layout/layout-header.js.map +1 -1
  19. package/dist/components/titan-layout/layout-header.module.less +5 -0
  20. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
  21. package/dist/components/titan-layout/layout-profile.js +1 -7
  22. package/dist/components/titan-layout/layout-profile.js.map +1 -1
  23. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +10 -17
  24. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
  25. package/dist/components/titan-layout/layout-sidebar-links-internal.js +34 -41
  26. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
  27. package/dist/components/titan-layout/layout-sidebar-links.d.ts +3 -3
  28. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
  29. package/dist/components/titan-layout/layout-sidebar-links.js +13 -13
  30. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
  31. package/dist/components/titan-layout/layout-sidebar.js +5 -3
  32. package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
  33. package/dist/components/titan-layout/titan-layout-links.d.ts +5 -0
  34. package/dist/components/titan-layout/titan-layout-links.d.ts.map +1 -0
  35. package/dist/components/titan-layout/titan-layout-links.js +34 -0
  36. package/dist/components/titan-layout/titan-layout-links.js.map +1 -0
  37. package/dist/components/titan-layout/titan-layout.d.ts +2 -3
  38. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
  39. package/dist/components/titan-layout/titan-layout.js +3 -3
  40. package/dist/components/titan-layout/titan-layout.js.map +1 -1
  41. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
  42. package/dist/index.d.ts +1 -5
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +0 -4
  45. package/dist/index.js.map +1 -1
  46. package/dist/test/data.d.ts +27 -2
  47. package/dist/test/data.d.ts.map +1 -1
  48. package/dist/test/data.js +181 -27
  49. package/dist/test/data.js.map +1 -1
  50. package/dist/utils/navigation-context.d.ts +3 -22
  51. package/dist/utils/navigation-context.d.ts.map +1 -1
  52. package/dist/utils/navigation-context.js +2 -10
  53. package/dist/utils/navigation-context.js.map +1 -1
  54. package/dist/utils/navigation.d.ts +2 -5
  55. package/dist/utils/navigation.d.ts.map +1 -1
  56. package/dist/utils/navigation.js.map +1 -1
  57. package/package.json +2 -2
  58. package/src/components/profile-dropdown/{profile-dropdown-tiny.stories.tsx → profile-dropdown-legacy.stories.tsx} +6 -6
  59. package/src/components/profile-dropdown/profile-dropdown-stacked.stories.tsx +12 -4
  60. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +16 -9
  61. package/src/components/profile-dropdown/profile-dropdown.tsx +2 -11
  62. package/src/components/titan-layout/interface.ts +19 -15
  63. package/src/components/titan-layout/layout-header-dark.tsx +1 -1
  64. package/src/components/titan-layout/layout-header-links.tsx +3 -6
  65. package/src/components/titan-layout/layout-header.module.less +5 -0
  66. package/src/components/titan-layout/layout-header.tsx +2 -2
  67. package/src/components/titan-layout/layout-profile.tsx +2 -6
  68. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +69 -81
  69. package/src/components/titan-layout/layout-sidebar-links.tsx +38 -24
  70. package/src/components/titan-layout/layout-sidebar.tsx +1 -1
  71. package/src/components/titan-layout/titan-layout-links.tsx +34 -0
  72. package/src/components/titan-layout/titan-layout.stories.tsx +34 -33
  73. package/src/components/titan-layout/titan-layout.tsx +5 -4
  74. package/src/index.ts +1 -11
  75. package/src/test/data.tsx +152 -39
  76. package/src/utils/navigation-context.tsx +9 -35
  77. package/src/utils/navigation.ts +3 -7
  78. package/dist/components/header-navigation/header-navigation-content.d.ts +0 -30
  79. package/dist/components/header-navigation/header-navigation-content.d.ts.map +0 -1
  80. package/dist/components/header-navigation/header-navigation-content.js +0 -58
  81. package/dist/components/header-navigation/header-navigation-content.js.map +0 -1
  82. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.d.ts +0 -9
  83. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.d.ts.map +0 -1
  84. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts +0 -12
  85. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts.map +0 -1
  86. package/dist/components/header-navigation/header-navigation-links.d.ts +0 -11
  87. package/dist/components/header-navigation/header-navigation-links.d.ts.map +0 -1
  88. package/dist/components/header-navigation/header-navigation-links.js +0 -62
  89. package/dist/components/header-navigation/header-navigation-links.js.map +0 -1
  90. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts +0 -12
  91. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts.map +0 -1
  92. package/dist/components/header-navigation/header-navigation-stories.module.less +0 -6
  93. package/dist/components/header-navigation/header-navigation-stories.module.less.d.ts +0 -3
  94. package/dist/components/header-navigation/header-navigation.d.ts +0 -59
  95. package/dist/components/header-navigation/header-navigation.d.ts.map +0 -1
  96. package/dist/components/header-navigation/header-navigation.js +0 -228
  97. package/dist/components/header-navigation/header-navigation.js.map +0 -1
  98. package/dist/components/header-navigation/header-navigation.module.less +0 -260
  99. package/dist/components/header-navigation/header-navigation.module.less.d.ts +0 -22
  100. package/dist/components/header-navigation/header-navigation.stories.d.ts +0 -12
  101. package/dist/components/header-navigation/header-navigation.stories.d.ts.map +0 -1
  102. package/dist/components/header-navigation/index.d.ts +0 -2
  103. package/dist/components/header-navigation/index.d.ts.map +0 -1
  104. package/dist/components/header-navigation/index.js +0 -3
  105. package/dist/components/header-navigation/index.js.map +0 -1
  106. package/dist/components/header-navigation/with-tooltip.d.ts +0 -4
  107. package/dist/components/header-navigation/with-tooltip.d.ts.map +0 -1
  108. package/dist/components/header-navigation/with-tooltip.js +0 -10
  109. package/dist/components/header-navigation/with-tooltip.js.map +0 -1
  110. package/dist/components/layout.stories.d.ts +0 -13
  111. package/dist/components/layout.stories.d.ts.map +0 -1
  112. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.d.ts +0 -9
  113. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.d.ts.map +0 -1
  114. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts +0 -18
  115. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts.map +0 -1
  116. package/dist/components/left-navigation/header-navigation-tiny-links.js +0 -79
  117. package/dist/components/left-navigation/header-navigation-tiny-links.js.map +0 -1
  118. package/dist/components/left-navigation/header-navigation-tiny.d.ts +0 -23
  119. package/dist/components/left-navigation/header-navigation-tiny.d.ts.map +0 -1
  120. package/dist/components/left-navigation/header-navigation-tiny.js +0 -32
  121. package/dist/components/left-navigation/header-navigation-tiny.js.map +0 -1
  122. package/dist/components/left-navigation/header-navigation-tiny.module.less +0 -117
  123. package/dist/components/left-navigation/header-navigation-tiny.module.less.d.ts +0 -15
  124. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts +0 -12
  125. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts.map +0 -1
  126. package/dist/components/left-navigation/index.d.ts +0 -5
  127. package/dist/components/left-navigation/index.d.ts.map +0 -1
  128. package/dist/components/left-navigation/index.js +0 -5
  129. package/dist/components/left-navigation/index.js.map +0 -1
  130. package/dist/components/left-navigation/interface-internal.d.ts +0 -10
  131. package/dist/components/left-navigation/interface-internal.d.ts.map +0 -1
  132. package/dist/components/left-navigation/interface-internal.js +0 -3
  133. package/dist/components/left-navigation/interface-internal.js.map +0 -1
  134. package/dist/components/left-navigation/interface.d.ts +0 -20
  135. package/dist/components/left-navigation/interface.d.ts.map +0 -1
  136. package/dist/components/left-navigation/interface.js +0 -3
  137. package/dist/components/left-navigation/interface.js.map +0 -1
  138. package/dist/components/left-navigation/side-navigation-context.d.ts +0 -8
  139. package/dist/components/left-navigation/side-navigation-context.d.ts.map +0 -1
  140. package/dist/components/left-navigation/side-navigation-context.js +0 -8
  141. package/dist/components/left-navigation/side-navigation-context.js.map +0 -1
  142. package/dist/components/left-navigation/side-navigation-links-internal.d.ts +0 -28
  143. package/dist/components/left-navigation/side-navigation-links-internal.d.ts.map +0 -1
  144. package/dist/components/left-navigation/side-navigation-links-internal.js +0 -89
  145. package/dist/components/left-navigation/side-navigation-links-internal.js.map +0 -1
  146. package/dist/components/left-navigation/side-navigation-links.d.ts +0 -6
  147. package/dist/components/left-navigation/side-navigation-links.d.ts.map +0 -1
  148. package/dist/components/left-navigation/side-navigation-links.js +0 -48
  149. package/dist/components/left-navigation/side-navigation-links.js.map +0 -1
  150. package/dist/components/left-navigation/side-navigation.d.ts +0 -29
  151. package/dist/components/left-navigation/side-navigation.d.ts.map +0 -1
  152. package/dist/components/left-navigation/side-navigation.js +0 -411
  153. package/dist/components/left-navigation/side-navigation.js.map +0 -1
  154. package/dist/components/left-navigation/side-navigation.module.less +0 -530
  155. package/dist/components/left-navigation/side-navigation.module.less.d.ts +0 -48
  156. package/dist/components/left-navigation/side-navigation.stories.d.ts +0 -17
  157. package/dist/components/left-navigation/side-navigation.stories.d.ts.map +0 -1
  158. package/dist/components/left-navigation/with-tooltip.d.ts +0 -4
  159. package/dist/components/left-navigation/with-tooltip.d.ts.map +0 -1
  160. package/dist/components/left-navigation/with-tooltip.js +0 -15
  161. package/dist/components/left-navigation/with-tooltip.js.map +0 -1
  162. package/dist/components/links.d.ts +0 -5
  163. package/dist/components/links.d.ts.map +0 -1
  164. package/dist/components/links.js +0 -35
  165. package/dist/components/links.js.map +0 -1
  166. package/dist/components/profile-dropdown/profile-dropdown-tiny.stories.d.ts.map +0 -1
  167. package/dist/components/titan-layout/layout-profile.stories.d.ts +0 -13
  168. package/dist/components/titan-layout/layout-profile.stories.d.ts.map +0 -1
  169. package/src/components/header-navigation/header-navigation-content.tsx +0 -120
  170. package/src/components/header-navigation/header-navigation-extra-stacked.stories.tsx +0 -19
  171. package/src/components/header-navigation/header-navigation-extra.stories.tsx +0 -142
  172. package/src/components/header-navigation/header-navigation-links.tsx +0 -141
  173. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +0 -146
  174. package/src/components/header-navigation/header-navigation-stories.module.less +0 -6
  175. package/src/components/header-navigation/header-navigation-stories.module.less.d.ts +0 -3
  176. package/src/components/header-navigation/header-navigation.module.less +0 -260
  177. package/src/components/header-navigation/header-navigation.module.less.d.ts +0 -22
  178. package/src/components/header-navigation/header-navigation.stories.tsx +0 -165
  179. package/src/components/header-navigation/header-navigation.tsx +0 -327
  180. package/src/components/header-navigation/index.ts +0 -1
  181. package/src/components/header-navigation/with-tooltip.tsx +0 -15
  182. package/src/components/layout.stories.tsx +0 -103
  183. package/src/components/left-navigation/header-navigation-extra-tiny.stories.tsx +0 -21
  184. package/src/components/left-navigation/header-navigation-tiny-links.tsx +0 -145
  185. package/src/components/left-navigation/header-navigation-tiny.module.less +0 -117
  186. package/src/components/left-navigation/header-navigation-tiny.module.less.d.ts +0 -15
  187. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +0 -178
  188. package/src/components/left-navigation/header-navigation-tiny.tsx +0 -65
  189. package/src/components/left-navigation/index.ts +0 -4
  190. package/src/components/left-navigation/interface-internal.ts +0 -11
  191. package/src/components/left-navigation/interface.ts +0 -26
  192. package/src/components/left-navigation/side-navigation-context.tsx +0 -13
  193. package/src/components/left-navigation/side-navigation-links-internal.tsx +0 -151
  194. package/src/components/left-navigation/side-navigation-links.tsx +0 -57
  195. package/src/components/left-navigation/side-navigation.module.less +0 -530
  196. package/src/components/left-navigation/side-navigation.module.less.d.ts +0 -48
  197. package/src/components/left-navigation/side-navigation.stories.tsx +0 -226
  198. package/src/components/left-navigation/side-navigation.tsx +0 -543
  199. package/src/components/left-navigation/with-tooltip.tsx +0 -16
  200. package/src/components/links.tsx +0 -54
  201. package/src/components/titan-layout/layout-profile.stories.tsx +0 -46
@@ -1,543 +0,0 @@
1
- import { Icon, Popover, Text, ThemeProvider } from '@servicetitan/anvil2';
2
- import SvgCollapse from '@servicetitan/anvil2/assets/icons/st/gnav_menu_collapse.svg';
3
- import SvgExpand from '@servicetitan/anvil2/assets/icons/st/gnav_menu_expand.svg';
4
- import { Headline } from '@servicetitan/design-system';
5
-
6
- import classNames from 'classnames';
7
- import {
8
- CSSProperties,
9
- Children,
10
- FC,
11
- Fragment,
12
- MouseEvent,
13
- ReactElement,
14
- isValidElement,
15
- useCallback,
16
- useContext,
17
- useEffect,
18
- useMemo,
19
- useRef,
20
- useState,
21
- } from 'react';
22
- import {
23
- NavigationItemData,
24
- NavigationLinkData,
25
- NavigationSubmenuData,
26
- NavigationSubmenuItemData,
27
- } from '../../utils/navigation';
28
- import {
29
- NavLinkComponentProps,
30
- NavigationActiveLinkMatcher,
31
- NavigationComponentContext,
32
- NavigationLocationContext,
33
- NavigationLocationInfo,
34
- } from '../../utils/navigation-context';
35
- import { getCounterTag, getSubmenuGroupTag } from '../../utils/side-nav';
36
- import { BadgeTag } from '../badge-tag';
37
- import {
38
- SideNavigationExpandedState,
39
- SideNavigationLinkProps,
40
- SideNavigationTriggerProps,
41
- } from './interface';
42
- import { NavigationComponentProps, SideNavigationExpandedProps } from './interface-internal';
43
- import { SideNavigationContext, SideNavigationContextType } from './side-navigation-context';
44
- import { InternalSideNavigationLink } from './side-navigation-links-internal';
45
- import * as Styles from './side-navigation.module.less';
46
- import { withTooltip } from './with-tooltip';
47
-
48
- type OptionalChildren<T> =
49
- | (ReactElement<T> | false | undefined | null)
50
- | (ReactElement<T> | false | undefined | null)[];
51
- export interface SideNavigationProps {
52
- /** container class name */
53
- className?: string;
54
- /** container id */
55
- id?: string;
56
- /** main navigation items */
57
- items?: NavigationItemData[];
58
- /** additional components */
59
- children?: OptionalChildren<SideNavigationTopProps>;
60
- /** is menu expanded */
61
- expanded?: SideNavigationExpandedState;
62
- /** show submenu in separate bar */
63
- appearance?: 'v1' | 'v2';
64
- /** expand change handler */
65
- onExpandedChange?(expanded: SideNavigationExpandedState): void;
66
- }
67
-
68
- const defaultContext: SideNavigationContextType = {
69
- styles: {
70
- popoverContent: {
71
- '--background-color-strong': '#24323C',
72
- 'color': 'var(--color-white)',
73
- } as CSSProperties,
74
- },
75
- };
76
-
77
- const useOutRef = (onOut: () => void) => {
78
- const ref = useRef<HTMLDivElement>(null);
79
-
80
- useEffect(() => {
81
- const elem = ref.current;
82
-
83
- if (elem) {
84
- let timeout: ReturnType<typeof setTimeout> | undefined = undefined;
85
- const onMouseLeave = () => {
86
- timeout = setTimeout(onOut, 500);
87
- };
88
- const onMouseEnter = () => {
89
- if (timeout) {
90
- clearTimeout(timeout);
91
- timeout = undefined;
92
- }
93
- };
94
-
95
- elem.addEventListener('mouseleave', onMouseLeave);
96
- elem.addEventListener('mouseenter', onMouseEnter);
97
- return () => {
98
- elem.removeEventListener('mouseleave', onMouseLeave);
99
- elem.removeEventListener('mouseenter', onMouseEnter);
100
- };
101
- }
102
- }, [onOut]);
103
-
104
- return ref;
105
- };
106
-
107
- const isLinkActive = (
108
- location: NavigationLocationInfo,
109
- link: NavigationLinkData,
110
- matcher: NavigationActiveLinkMatcher
111
- ) => {
112
- if (typeof link.isActive === 'boolean') {
113
- return link.isActive;
114
- }
115
-
116
- if (typeof link.isActive === 'function') {
117
- return link.isActive(location.pathname);
118
- }
119
-
120
- return matcher?.(location, link) ?? false;
121
- };
122
-
123
- function SideNavigationElement({
124
- className,
125
- children,
126
- expanded,
127
- id,
128
- items,
129
- appearance,
130
- onExpandedChange,
131
- }: SideNavigationProps) {
132
- const NavigationComponent = useContext(NavigationComponentContext);
133
- const locationInfo = useContext(NavigationLocationContext);
134
- const [submenuDrawerItemId, setSubmenuDrawerItemId] = useState<string>();
135
- const isExperimental = appearance === 'v2';
136
- const isExperimentalExpanded = isExperimental && !expanded?.collapsedBar;
137
-
138
- const activeItem = useMemo(
139
- () =>
140
- items?.find(item =>
141
- isLinkActive(locationInfo.location, item, locationInfo.isLinkActive)
142
- ),
143
- [locationInfo, items]
144
- );
145
- const activeId = activeItem?.id;
146
-
147
- const submenu = useMemo(() => {
148
- if (!isExperimental) {
149
- return undefined;
150
- }
151
-
152
- if (isExperimentalExpanded) {
153
- const item = activeId ? items?.find(item => item.id === activeId) : undefined;
154
-
155
- return item?.submenu ? { item, bar: true, drawer: false } : undefined;
156
- } else if (submenuDrawerItemId) {
157
- const item = items?.find(item => item.id === submenuDrawerItemId);
158
-
159
- return item?.submenu ? { item, bar: false, drawer: true } : undefined;
160
- }
161
-
162
- return undefined;
163
- }, [activeId, items, isExperimental, isExperimentalExpanded, submenuDrawerItemId]);
164
- const isExpanded = isExperimental ? isExperimentalExpanded && !!submenu : !!expanded?.bar;
165
-
166
- useEffect(() => {
167
- if (isExperimentalExpanded) {
168
- setSubmenuDrawerItemId(undefined);
169
- }
170
- }, [isExperimentalExpanded]);
171
-
172
- const { childTop } = useMemo(
173
- () =>
174
- Children.toArray(children).reduce(
175
- (out, item) => {
176
- if (
177
- item &&
178
- isValidElement(item) &&
179
- item.type &&
180
- typeof item.type !== 'string' &&
181
- item.type.name === SideNavigationTop.name
182
- ) {
183
- out.childTop = item;
184
- }
185
- return out;
186
- },
187
- {} as { childTop?: ReactElement }
188
- ),
189
- [children]
190
- );
191
-
192
- const canActivateSubmenuBarDrawer = isExperimental && !!expanded?.collapsedBar;
193
- const hideSubmenuBarDrawer = useCallback(() => {
194
- setSubmenuDrawerItemId(undefined);
195
- }, []);
196
-
197
- const openSubmenuBarDrawer = (e: MouseEvent<HTMLDivElement>, item: NavigationItemData) => {
198
- if (!isExperimental || !expanded?.collapsedBar) {
199
- return;
200
- }
201
-
202
- if (item.submenu) {
203
- setSubmenuDrawerItemId(item.id);
204
-
205
- if (item.id === activeId) {
206
- e.preventDefault();
207
- e.stopPropagation();
208
- }
209
- }
210
- };
211
-
212
- const handleExpandedChange = useCallback(
213
- (value: boolean) => {
214
- onExpandedChange?.(
215
- isExperimental ? { bar: false, collapsedBar: !value } : { bar: value }
216
- );
217
- setSubmenuDrawerItemId(undefined);
218
- },
219
- [isExperimental, onExpandedChange]
220
- );
221
-
222
- return (
223
- <SideNavigationContext.Provider value={defaultContext}>
224
- <div
225
- className={classNames(
226
- Styles.sideNav,
227
- isExperimental ? Styles.sideNavV2 : Styles.sideNavV1,
228
- isExpanded ? Styles.sideNavExpanded : Styles.sideNavSlim,
229
- className
230
- )}
231
- id={id}
232
- data-cy="side-navigation"
233
- >
234
- <ThemeProvider mode="dark" className={Styles.sideNavMain}>
235
- <div className={Styles.sideNavNavigation}>
236
- {isExperimental && !isExpanded && !!activeItem?.submenu && (
237
- <SideNavigationOptionsToggle
238
- appearance="expand"
239
- onExpandedChange={handleExpandedChange}
240
- />
241
- )}
242
-
243
- {childTop}
244
- <div className={Styles.sideNavContent} data-cy="navigation-items">
245
- {items?.map(item =>
246
- item.submenu && !isExperimental ? (
247
- <SideNavigationGroupItem
248
- key={item.id}
249
- expanded={expanded}
250
- isGroupActive={activeItem?.id === item.id}
251
- onExpandedChange={onExpandedChange}
252
- navigationComponent={NavigationComponent}
253
- {...item}
254
- />
255
- ) : (
256
- <div
257
- key={item.id}
258
- onClickCapture={
259
- canActivateSubmenuBarDrawer
260
- ? item.submenu
261
- ? e => openSubmenuBarDrawer(e, item)
262
- : hideSubmenuBarDrawer
263
- : undefined
264
- }
265
- >
266
- <InternalSideNavigationLink
267
- submenuExpanded={undefined}
268
- navigationComponent={NavigationComponent}
269
- {...item}
270
- tag={getSubmenuGroupTag(
271
- item.submenu,
272
- getCounterTag(item.counter, item.tag)
273
- )}
274
- />
275
- </div>
276
- )
277
- )}
278
- </div>
279
- </div>
280
-
281
- {!!submenu && (
282
- <SubmenuBar
283
- bar={submenu.bar}
284
- item={submenu.item}
285
- handleExpandedChange={handleExpandedChange}
286
- handleLeave={hideSubmenuBarDrawer}
287
- navigationComponent={NavigationComponent}
288
- />
289
- )}
290
- </ThemeProvider>
291
-
292
- {!isExperimental && (
293
- <div className={Styles.sideNavFooter}>
294
- <div className={Styles.divider} />
295
- <div className={Styles.sideNavBottom}>
296
- <SideNavigationOptionsToggle
297
- appearance={isExpanded ? 'collapse-button' : 'expand'}
298
- onExpandedChange={handleExpandedChange}
299
- />
300
- </div>
301
- </div>
302
- )}
303
- </div>
304
- </SideNavigationContext.Provider>
305
- );
306
- }
307
-
308
- const SubmenuBar: FC<{
309
- item: NavigationItemData;
310
- bar: boolean;
311
- navigationComponent: FC<NavLinkComponentProps>;
312
- handleExpandedChange(value: boolean): void;
313
- handleLeave(): void;
314
- }> = ({
315
- bar,
316
- item,
317
- navigationComponent: NavigationComponent,
318
- handleExpandedChange,
319
- handleLeave,
320
- }) => {
321
- const outRef = useOutRef(handleLeave);
322
-
323
- return (
324
- <div className={bar ? Styles.sideNavSubmenuBar : Styles.sideNavSubmenuDrawer} ref={outRef}>
325
- <div className="d-f justify-content-between align-items-center m-t-2 m-l-3">
326
- <Headline size="small" className="c-white m-b-0-i">
327
- {item.title}
328
- </Headline>
329
-
330
- {bar && (
331
- <SideNavigationOptionsToggle
332
- appearance="collapse"
333
- onExpandedChange={handleExpandedChange}
334
- />
335
- )}
336
- </div>
337
-
338
- <div className={Styles.submenuBar}>
339
- <SideNavigationGroupContent
340
- groups={item.submenu?.groups ?? []}
341
- navigationComponent={NavigationComponent}
342
- />
343
- </div>
344
- </div>
345
- );
346
- };
347
- export interface SideNavigationTopProps {
348
- children: OptionalChildren<SideNavigationLinkProps | SideNavigationTriggerProps>;
349
- }
350
- function SideNavigationTopElement({ children }: SideNavigationTopProps) {
351
- const list = Children.map(children, child => {
352
- return child && isValidElement(child) ? child : null;
353
- });
354
- return list?.length ? (
355
- <Fragment>
356
- <ThemeProvider mode="dark" className={Styles.sideNavTop} data-cy="navigation-items-top">
357
- {list}
358
- </ThemeProvider>
359
- <div className={Styles.divider} />
360
- </Fragment>
361
- ) : null;
362
- }
363
- const SideNavigationTop: FC<SideNavigationTopProps> = SideNavigationTopElement;
364
-
365
- /** Side Navigation menu item */
366
- const SideNavigationGroupItem: FC<
367
- NavigationItemData &
368
- SideNavigationExpandedProps &
369
- NavigationComponentProps & {
370
- isGroupActive: boolean;
371
- onExpandedChange: undefined | ((expanded: SideNavigationExpandedState) => void);
372
- }
373
- > = ({ onExpandedChange, isGroupActive, ...props }) => {
374
- const isSubmenuExpanded = !!props.id && props.expanded?.expandedSubmenu === props.id;
375
- const onExpandToggle = useCallback(
376
- (e: MouseEvent<never>) => {
377
- e.preventDefault();
378
- e.stopPropagation();
379
-
380
- onExpandedChange?.({
381
- bar: true,
382
- expandedSubmenu: isSubmenuExpanded ? undefined : props.id,
383
- });
384
- },
385
- [props.id, isSubmenuExpanded, onExpandedChange]
386
- );
387
-
388
- const tag = getSubmenuGroupTag(props.submenu, getCounterTag(props.counter, props.tag));
389
- const context = useContext(SideNavigationContext);
390
-
391
- return props.expanded?.bar ? (
392
- <div className={classNames(Styles.navigationGroupWrapper)}>
393
- <div className={Styles.navigationGroupItem}>
394
- <InternalSideNavigationLink
395
- {...props}
396
- submenuExpanded={isSubmenuExpanded}
397
- onExpandToggle={onExpandToggle}
398
- tag={tag}
399
- />
400
- </div>
401
- <div
402
- className={classNames(Styles.submenuWrapper, {
403
- [Styles.submenuWrapperCollapsed]: !isSubmenuExpanded,
404
- })}
405
- >
406
- <div className={Styles.submenu}>
407
- <SideNavigationGroupContent
408
- groups={props.submenu?.groups ?? []}
409
- navigationComponent={props.navigationComponent}
410
- />
411
- </div>
412
- </div>
413
- </div>
414
- ) : (
415
- <Popover placement="right-start" openOnHover delay={500}>
416
- <Popover.Trigger>
417
- {(triggerProps: any) => (
418
- <div {...triggerProps}>
419
- <InternalSideNavigationLink
420
- {...props}
421
- submenuExpanded={undefined}
422
- tag={tag}
423
- />
424
- </div>
425
- )}
426
- </Popover.Trigger>
427
- <Popover.Content style={context.styles.popoverContent} className="z-global-nav-i">
428
- <div className={Styles.submenuPopover}>
429
- <Headline size="small" className="c-white m-b-half-i m-t-1">
430
- {props.title}
431
- </Headline>
432
- <SideNavigationGroupContent
433
- groups={props.submenu?.groups ?? []}
434
- navigationComponent={props.navigationComponent}
435
- />
436
- </div>
437
- </Popover.Content>
438
- </Popover>
439
- );
440
- };
441
- const SideNavigationGroupContent: FC<NavigationSubmenuData & NavigationComponentProps> = ({
442
- groups,
443
- navigationComponent,
444
- }) => {
445
- return (
446
- <Fragment>
447
- {groups.reduce((out, group, index) => {
448
- if (!group.links.length) {
449
- return out;
450
- }
451
-
452
- const title = group.title?.trim() ?? '';
453
- /* eslint-disable react/no-array-index-key */
454
- out.push(
455
- <Text
456
- key={`:group:${index}:title`}
457
- variant="eyebrow"
458
- className={classNames(Styles.submenuGroupHeader, {
459
- [Styles.submenuGroupHeaderEmpty]: !title,
460
- })}
461
- >
462
- {title}
463
- </Text>
464
- );
465
- out.push(
466
- ...group.links.map((link, index) => (
467
- <SideNavigationGroupLink
468
- key={`:${link.id}:${index}`}
469
- {...link}
470
- navigationComponent={navigationComponent}
471
- />
472
- ))
473
- );
474
- /* eslint-enable react/no-array-index-key */
475
-
476
- return out;
477
- }, [] as ReactElement[])}
478
- </Fragment>
479
- );
480
- };
481
- const SideNavigationGroupLink: FC<NavigationSubmenuItemData & NavigationComponentProps> = ({
482
- id,
483
- counter,
484
- tag,
485
- title,
486
- to,
487
- isActive,
488
- navigationComponent: NavigationComponent,
489
- }) => {
490
- return (
491
- <NavigationComponent
492
- data-cy={`navigation-item-${id}`}
493
- data-pendo={`navigation-item-${id}`}
494
- key={id}
495
- to={to}
496
- className={classNames(Styles.submenuLink, {
497
- [Styles.submenuLinkActive]: isActive === true,
498
- })}
499
- isActive={typeof isActive === 'function' ? isActive : undefined}
500
- activeClassName={Styles.submenuLinkActive}
501
- >
502
- <span>{title}</span>
503
- <BadgeTag data={getCounterTag(counter, tag)} className={Styles.submenuLinkCounter} />
504
- </NavigationComponent>
505
- );
506
- };
507
-
508
- /** Side Navigation options toggle */
509
- const SideNavigationOptionsToggle: FC<{
510
- appearance: 'expand' | 'collapse' | 'collapse-button';
511
- onExpandedChange?(expanded: boolean): void;
512
- }> = ({ appearance, onExpandedChange }) =>
513
- withTooltip(
514
- <div
515
- data-cy="navigation-left-options"
516
- data-pendo="navigation-left-options"
517
- className={classNames(Styles.optionsItem)}
518
- onClick={() => onExpandedChange?.(appearance === 'expand')}
519
- >
520
- <div className={Styles.optionsItemContent}>
521
- <div className={Styles.optionsIconWrapper}>
522
- <Icon
523
- className={Styles.optionsIcon}
524
- svg={appearance === 'expand' ? SvgExpand : SvgCollapse}
525
- />
526
- </div>
527
-
528
- {appearance === 'collapse-button' && (
529
- <span className={Styles.optionsItemText}>Collapse Menu</span>
530
- )}
531
- </div>
532
- </div>,
533
- appearance === 'expand'
534
- ? 'Expand Menu'
535
- : appearance === 'collapse'
536
- ? 'Collapse Menu'
537
- : undefined,
538
- 'right'
539
- );
540
-
541
- export const SideNavigation = Object.assign(SideNavigationElement, {
542
- Top: SideNavigationTop,
543
- });
@@ -1,16 +0,0 @@
1
- import { Tooltip, TooltipProps } from '@servicetitan/anvil2';
2
- import { ReactElement } from 'react';
3
-
4
- export const withTooltip = (
5
- element: ReactElement,
6
- tooltip: string | undefined,
7
- placement: TooltipProps['placement'] = 'bottom'
8
- ) =>
9
- tooltip ? (
10
- <Tooltip placement={placement}>
11
- <Tooltip.Content>{tooltip}</Tooltip.Content>
12
- <Tooltip.Trigger>{element}</Tooltip.Trigger>
13
- </Tooltip>
14
- ) : (
15
- element
16
- );
@@ -1,54 +0,0 @@
1
- import { FC } from 'react';
2
- import {
3
- HeaderNavigationLinkProps,
4
- HeaderNavigationTriggerProps,
5
- } from '../utils/navigation-legacy';
6
- import {
7
- HeaderNavigationLink as HeaderNavigationLinkLegacy,
8
- HeaderNavigationTrigger as HeaderNavigationTriggerLegacy,
9
- } from './header-navigation/header-navigation-links';
10
- import { useTitanLayoutPlacementContext } from './titan-layout';
11
- import {
12
- LayoutHeaderNavigationLink,
13
- LayoutHeaderNavigationTrigger,
14
- } from './titan-layout/layout-header-links';
15
- import {
16
- TitanLayoutSidebarLink,
17
- TitanLayoutSidebarTrigger,
18
- } from './titan-layout/layout-sidebar-links';
19
-
20
- export const HeaderNavigationLink: FC<HeaderNavigationLinkProps> = props => {
21
- const placement = useTitanLayoutPlacementContext();
22
-
23
- return placement === 'top' ? (
24
- <LayoutHeaderNavigationLink {...props} />
25
- ) : placement === 'side' ? (
26
- <TitanLayoutSidebarLink
27
- id={props.id}
28
- icon={props.icon}
29
- iconActive={props.iconActive}
30
- to={props.to}
31
- title={props.title}
32
- counter={props.counter}
33
- />
34
- ) : (
35
- <HeaderNavigationLinkLegacy {...props} />
36
- );
37
- };
38
-
39
- export const HeaderNavigationTrigger: FC<HeaderNavigationTriggerProps> = props => {
40
- const placement = useTitanLayoutPlacementContext();
41
-
42
- return placement === 'top' ? (
43
- <LayoutHeaderNavigationTrigger {...props} />
44
- ) : placement === 'side' ? (
45
- <TitanLayoutSidebarTrigger
46
- id={props.id}
47
- title={props.title}
48
- icon={props.icon}
49
- iconActive={props.iconActive}
50
- />
51
- ) : (
52
- <HeaderNavigationTriggerLegacy {...props} />
53
- );
54
- };
@@ -1,46 +0,0 @@
1
- import { ReactElement } from 'react';
2
- import { withAnvil, withDefaultRedirects, withMemoryRouter } from '../../test/data';
3
- import { ProfileDropdown } from './layout-profile';
4
- import { TitanLayout } from './titan-layout';
5
-
6
- const withTitanLayout = (element: ReactElement) => () => (
7
- <TitanLayout navigationMainItems={[]} profile={element}>
8
- profile
9
- </TitanLayout>
10
- );
11
-
12
- export default {
13
- title: 'Navigation/TitanLayoutProfile',
14
- component: ProfileDropdown,
15
- decorators: [withDefaultRedirects, withMemoryRouter, withAnvil],
16
- parameters: {},
17
- };
18
-
19
- export const ProfileDefault = withTitanLayout(
20
- <ProfileDropdown>
21
- <ProfileDropdown.Link id="first" to="https://google.com" external>
22
- first link
23
- </ProfileDropdown.Link>
24
- <ProfileDropdown.Section id="second" onClick={() => alert('second click')}>
25
- second link
26
- </ProfileDropdown.Section>
27
- <ProfileDropdown.Divider />
28
- <ProfileDropdown.Section id="content">some content</ProfileDropdown.Section>
29
- <ProfileDropdown.Divider />
30
- <ProfileDropdown.Divider />
31
- <ProfileDropdown.Divider />
32
- <ProfileDropdown.Link id="third" to="third">
33
- third link
34
- </ProfileDropdown.Link>
35
- <ProfileDropdown.Divider />
36
- <ProfileDropdown.Section
37
- id="forth"
38
- onClick={() => alert('forth click')}
39
- text="Sign Out user"
40
- >
41
- Sign Out
42
- <span className="c-neutral-60 m-l-1">user</span>
43
- </ProfileDropdown.Section>
44
- <ProfileDropdown.Divider />
45
- </ProfileDropdown>
46
- );