@servicetitan/navigation 12.0.3 → 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 (196) 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-links.d.ts +3 -3
  12. package/dist/components/titan-layout/layout-header-links.d.ts.map +1 -1
  13. package/dist/components/titan-layout/layout-header-links.js.map +1 -1
  14. package/dist/components/titan-layout/layout-header.d.ts +2 -2
  15. package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
  16. package/dist/components/titan-layout/layout-header.js.map +1 -1
  17. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
  18. package/dist/components/titan-layout/layout-profile.js +1 -7
  19. package/dist/components/titan-layout/layout-profile.js.map +1 -1
  20. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +10 -17
  21. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
  22. package/dist/components/titan-layout/layout-sidebar-links-internal.js +34 -41
  23. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
  24. package/dist/components/titan-layout/layout-sidebar-links.d.ts +3 -3
  25. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
  26. package/dist/components/titan-layout/layout-sidebar-links.js +13 -13
  27. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
  28. package/dist/components/titan-layout/layout-sidebar.js +5 -3
  29. package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
  30. package/dist/components/titan-layout/titan-layout-links.d.ts +5 -0
  31. package/dist/components/titan-layout/titan-layout-links.d.ts.map +1 -0
  32. package/dist/components/titan-layout/titan-layout-links.js +34 -0
  33. package/dist/components/titan-layout/titan-layout-links.js.map +1 -0
  34. package/dist/components/titan-layout/titan-layout.d.ts +2 -3
  35. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
  36. package/dist/components/titan-layout/titan-layout.js +3 -3
  37. package/dist/components/titan-layout/titan-layout.js.map +1 -1
  38. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
  39. package/dist/index.d.ts +1 -5
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +0 -4
  42. package/dist/index.js.map +1 -1
  43. package/dist/test/data.d.ts +27 -2
  44. package/dist/test/data.d.ts.map +1 -1
  45. package/dist/test/data.js +181 -27
  46. package/dist/test/data.js.map +1 -1
  47. package/dist/utils/navigation-context.d.ts +3 -22
  48. package/dist/utils/navigation-context.d.ts.map +1 -1
  49. package/dist/utils/navigation-context.js +2 -10
  50. package/dist/utils/navigation-context.js.map +1 -1
  51. package/dist/utils/navigation.d.ts +2 -5
  52. package/dist/utils/navigation.d.ts.map +1 -1
  53. package/dist/utils/navigation.js.map +1 -1
  54. package/package.json +2 -2
  55. package/src/components/profile-dropdown/{profile-dropdown-tiny.stories.tsx → profile-dropdown-legacy.stories.tsx} +6 -6
  56. package/src/components/profile-dropdown/profile-dropdown-stacked.stories.tsx +12 -4
  57. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +16 -9
  58. package/src/components/profile-dropdown/profile-dropdown.tsx +2 -11
  59. package/src/components/titan-layout/interface.ts +19 -15
  60. package/src/components/titan-layout/layout-header-links.tsx +3 -6
  61. package/src/components/titan-layout/layout-header.tsx +2 -2
  62. package/src/components/titan-layout/layout-profile.tsx +2 -6
  63. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +69 -81
  64. package/src/components/titan-layout/layout-sidebar-links.tsx +38 -24
  65. package/src/components/titan-layout/layout-sidebar.tsx +1 -1
  66. package/src/components/titan-layout/titan-layout-links.tsx +34 -0
  67. package/src/components/titan-layout/titan-layout.stories.tsx +34 -33
  68. package/src/components/titan-layout/titan-layout.tsx +5 -4
  69. package/src/index.ts +1 -11
  70. package/src/test/data.tsx +152 -39
  71. package/src/utils/navigation-context.tsx +9 -35
  72. package/src/utils/navigation.ts +3 -7
  73. package/dist/components/header-navigation/header-navigation-content.d.ts +0 -30
  74. package/dist/components/header-navigation/header-navigation-content.d.ts.map +0 -1
  75. package/dist/components/header-navigation/header-navigation-content.js +0 -58
  76. package/dist/components/header-navigation/header-navigation-content.js.map +0 -1
  77. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.d.ts +0 -9
  78. package/dist/components/header-navigation/header-navigation-extra-stacked.stories.d.ts.map +0 -1
  79. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts +0 -12
  80. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts.map +0 -1
  81. package/dist/components/header-navigation/header-navigation-links.d.ts +0 -11
  82. package/dist/components/header-navigation/header-navigation-links.d.ts.map +0 -1
  83. package/dist/components/header-navigation/header-navigation-links.js +0 -62
  84. package/dist/components/header-navigation/header-navigation-links.js.map +0 -1
  85. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts +0 -12
  86. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts.map +0 -1
  87. package/dist/components/header-navigation/header-navigation-stories.module.less +0 -6
  88. package/dist/components/header-navigation/header-navigation-stories.module.less.d.ts +0 -3
  89. package/dist/components/header-navigation/header-navigation.d.ts +0 -59
  90. package/dist/components/header-navigation/header-navigation.d.ts.map +0 -1
  91. package/dist/components/header-navigation/header-navigation.js +0 -228
  92. package/dist/components/header-navigation/header-navigation.js.map +0 -1
  93. package/dist/components/header-navigation/header-navigation.module.less +0 -260
  94. package/dist/components/header-navigation/header-navigation.module.less.d.ts +0 -22
  95. package/dist/components/header-navigation/header-navigation.stories.d.ts +0 -12
  96. package/dist/components/header-navigation/header-navigation.stories.d.ts.map +0 -1
  97. package/dist/components/header-navigation/index.d.ts +0 -2
  98. package/dist/components/header-navigation/index.d.ts.map +0 -1
  99. package/dist/components/header-navigation/index.js +0 -3
  100. package/dist/components/header-navigation/index.js.map +0 -1
  101. package/dist/components/header-navigation/with-tooltip.d.ts +0 -4
  102. package/dist/components/header-navigation/with-tooltip.d.ts.map +0 -1
  103. package/dist/components/header-navigation/with-tooltip.js +0 -10
  104. package/dist/components/header-navigation/with-tooltip.js.map +0 -1
  105. package/dist/components/layout.stories.d.ts +0 -13
  106. package/dist/components/layout.stories.d.ts.map +0 -1
  107. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.d.ts +0 -9
  108. package/dist/components/left-navigation/header-navigation-extra-tiny.stories.d.ts.map +0 -1
  109. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts +0 -18
  110. package/dist/components/left-navigation/header-navigation-tiny-links.d.ts.map +0 -1
  111. package/dist/components/left-navigation/header-navigation-tiny-links.js +0 -79
  112. package/dist/components/left-navigation/header-navigation-tiny-links.js.map +0 -1
  113. package/dist/components/left-navigation/header-navigation-tiny.d.ts +0 -23
  114. package/dist/components/left-navigation/header-navigation-tiny.d.ts.map +0 -1
  115. package/dist/components/left-navigation/header-navigation-tiny.js +0 -32
  116. package/dist/components/left-navigation/header-navigation-tiny.js.map +0 -1
  117. package/dist/components/left-navigation/header-navigation-tiny.module.less +0 -117
  118. package/dist/components/left-navigation/header-navigation-tiny.module.less.d.ts +0 -15
  119. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts +0 -12
  120. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts.map +0 -1
  121. package/dist/components/left-navigation/index.d.ts +0 -5
  122. package/dist/components/left-navigation/index.d.ts.map +0 -1
  123. package/dist/components/left-navigation/index.js +0 -5
  124. package/dist/components/left-navigation/index.js.map +0 -1
  125. package/dist/components/left-navigation/interface-internal.d.ts +0 -10
  126. package/dist/components/left-navigation/interface-internal.d.ts.map +0 -1
  127. package/dist/components/left-navigation/interface-internal.js +0 -3
  128. package/dist/components/left-navigation/interface-internal.js.map +0 -1
  129. package/dist/components/left-navigation/interface.d.ts +0 -20
  130. package/dist/components/left-navigation/interface.d.ts.map +0 -1
  131. package/dist/components/left-navigation/interface.js +0 -3
  132. package/dist/components/left-navigation/interface.js.map +0 -1
  133. package/dist/components/left-navigation/side-navigation-context.d.ts +0 -8
  134. package/dist/components/left-navigation/side-navigation-context.d.ts.map +0 -1
  135. package/dist/components/left-navigation/side-navigation-context.js +0 -8
  136. package/dist/components/left-navigation/side-navigation-context.js.map +0 -1
  137. package/dist/components/left-navigation/side-navigation-links-internal.d.ts +0 -28
  138. package/dist/components/left-navigation/side-navigation-links-internal.d.ts.map +0 -1
  139. package/dist/components/left-navigation/side-navigation-links-internal.js +0 -89
  140. package/dist/components/left-navigation/side-navigation-links-internal.js.map +0 -1
  141. package/dist/components/left-navigation/side-navigation-links.d.ts +0 -6
  142. package/dist/components/left-navigation/side-navigation-links.d.ts.map +0 -1
  143. package/dist/components/left-navigation/side-navigation-links.js +0 -48
  144. package/dist/components/left-navigation/side-navigation-links.js.map +0 -1
  145. package/dist/components/left-navigation/side-navigation.d.ts +0 -29
  146. package/dist/components/left-navigation/side-navigation.d.ts.map +0 -1
  147. package/dist/components/left-navigation/side-navigation.js +0 -411
  148. package/dist/components/left-navigation/side-navigation.js.map +0 -1
  149. package/dist/components/left-navigation/side-navigation.module.less +0 -530
  150. package/dist/components/left-navigation/side-navigation.module.less.d.ts +0 -48
  151. package/dist/components/left-navigation/side-navigation.stories.d.ts +0 -17
  152. package/dist/components/left-navigation/side-navigation.stories.d.ts.map +0 -1
  153. package/dist/components/left-navigation/with-tooltip.d.ts +0 -4
  154. package/dist/components/left-navigation/with-tooltip.d.ts.map +0 -1
  155. package/dist/components/left-navigation/with-tooltip.js +0 -15
  156. package/dist/components/left-navigation/with-tooltip.js.map +0 -1
  157. package/dist/components/links.d.ts +0 -5
  158. package/dist/components/links.d.ts.map +0 -1
  159. package/dist/components/links.js +0 -35
  160. package/dist/components/links.js.map +0 -1
  161. package/dist/components/profile-dropdown/profile-dropdown-tiny.stories.d.ts.map +0 -1
  162. package/dist/components/titan-layout/layout-profile.stories.d.ts +0 -13
  163. package/dist/components/titan-layout/layout-profile.stories.d.ts.map +0 -1
  164. package/src/components/header-navigation/header-navigation-content.tsx +0 -120
  165. package/src/components/header-navigation/header-navigation-extra-stacked.stories.tsx +0 -19
  166. package/src/components/header-navigation/header-navigation-extra.stories.tsx +0 -142
  167. package/src/components/header-navigation/header-navigation-links.tsx +0 -141
  168. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +0 -146
  169. package/src/components/header-navigation/header-navigation-stories.module.less +0 -6
  170. package/src/components/header-navigation/header-navigation-stories.module.less.d.ts +0 -3
  171. package/src/components/header-navigation/header-navigation.module.less +0 -260
  172. package/src/components/header-navigation/header-navigation.module.less.d.ts +0 -22
  173. package/src/components/header-navigation/header-navigation.stories.tsx +0 -165
  174. package/src/components/header-navigation/header-navigation.tsx +0 -327
  175. package/src/components/header-navigation/index.ts +0 -1
  176. package/src/components/header-navigation/with-tooltip.tsx +0 -15
  177. package/src/components/layout.stories.tsx +0 -103
  178. package/src/components/left-navigation/header-navigation-extra-tiny.stories.tsx +0 -21
  179. package/src/components/left-navigation/header-navigation-tiny-links.tsx +0 -145
  180. package/src/components/left-navigation/header-navigation-tiny.module.less +0 -117
  181. package/src/components/left-navigation/header-navigation-tiny.module.less.d.ts +0 -15
  182. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +0 -178
  183. package/src/components/left-navigation/header-navigation-tiny.tsx +0 -65
  184. package/src/components/left-navigation/index.ts +0 -4
  185. package/src/components/left-navigation/interface-internal.ts +0 -11
  186. package/src/components/left-navigation/interface.ts +0 -26
  187. package/src/components/left-navigation/side-navigation-context.tsx +0 -13
  188. package/src/components/left-navigation/side-navigation-links-internal.tsx +0 -151
  189. package/src/components/left-navigation/side-navigation-links.tsx +0 -57
  190. package/src/components/left-navigation/side-navigation.module.less +0 -530
  191. package/src/components/left-navigation/side-navigation.module.less.d.ts +0 -48
  192. package/src/components/left-navigation/side-navigation.stories.tsx +0 -226
  193. package/src/components/left-navigation/side-navigation.tsx +0 -543
  194. package/src/components/left-navigation/with-tooltip.tsx +0 -16
  195. package/src/components/links.tsx +0 -54
  196. 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
- );