@servicetitan/navigation 13.0.0-canary.256.b43c6d7.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/counter-tag.d.ts +1 -1
- package/dist/components/counter-tag.d.ts.map +1 -1
- package/dist/components/counter-tag.js.map +1 -1
- package/dist/components/profile-dropdown/interface.d.ts +55 -0
- package/dist/components/profile-dropdown/interface.d.ts.map +1 -0
- package/dist/components/profile-dropdown/interface.js +3 -0
- package/dist/components/profile-dropdown/interface.js.map +1 -0
- package/dist/components/profile-dropdown/profile-dropdown-legacy.stories.d.ts +5 -1
- package/dist/components/profile-dropdown/profile-dropdown-legacy.stories.d.ts.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.d.ts +5 -1
- package/dist/components/profile-dropdown/profile-dropdown-stacked.stories.d.ts.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.d.ts +9 -79
- package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.js +17 -14
- package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts +5 -1
- package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts.map +1 -1
- package/dist/components/titan-layout/interface-internal.d.ts +12 -0
- package/dist/components/titan-layout/interface-internal.d.ts.map +1 -1
- package/dist/components/titan-layout/interface-internal.js.map +1 -1
- package/dist/components/titan-layout/interface.d.ts +60 -4
- package/dist/components/titan-layout/interface.d.ts.map +1 -1
- package/dist/components/titan-layout/interface.js.map +1 -1
- package/dist/components/titan-layout/layout-header-dark.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-header-dark.js +24 -12
- package/dist/components/titan-layout/layout-header-dark.js.map +1 -1
- package/dist/components/titan-layout/layout-header-links-internal.d.ts +22 -3
- package/dist/components/titan-layout/layout-header-links-internal.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-header-links-internal.js +15 -18
- package/dist/components/titan-layout/layout-header-links-internal.js.map +1 -1
- package/dist/components/titan-layout/layout-header-links.d.ts +2 -3
- package/dist/components/titan-layout/layout-header-links.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-header-links.js +25 -5
- package/dist/components/titan-layout/layout-header-links.js.map +1 -1
- package/dist/components/titan-layout/layout-header.d.ts +2 -0
- package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-header.js +25 -16
- package/dist/components/titan-layout/layout-header.js.map +1 -1
- package/dist/components/titan-layout/layout-header.module.less +37 -1
- package/dist/components/titan-layout/layout-header.module.less.d.ts +3 -0
- package/dist/components/titan-layout/layout-profile.d.ts +8 -5
- package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.js +29 -21
- package/dist/components/titan-layout/layout-profile.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +48 -24
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.js +62 -51
- package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links.d.ts +2 -2
- package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links.js +27 -14
- package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.d.ts +1 -1
- package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.js +81 -104
- package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +74 -22
- package/dist/components/titan-layout/titan-layout-default.stories.d.ts +16 -0
- package/dist/components/titan-layout/titan-layout-default.stories.d.ts.map +1 -0
- package/dist/components/titan-layout/titan-layout-legacy.stories.d.ts +10 -0
- package/dist/components/titan-layout/titan-layout-legacy.stories.d.ts.map +1 -0
- package/dist/components/titan-layout/titan-layout-stacked.stories.d.ts +10 -0
- package/dist/components/titan-layout/titan-layout-stacked.stories.d.ts.map +1 -0
- package/dist/components/titan-layout/titan-layout.d.ts +28 -1
- package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.js +30 -11
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/test/data.d.ts +0 -22
- package/dist/test/data.d.ts.map +1 -1
- package/dist/test/data.js +0 -197
- package/dist/test/data.js.map +1 -1
- package/dist/test/titan-layout.d.ts +16 -0
- package/dist/test/titan-layout.d.ts.map +1 -0
- package/dist/test/titan-layout.js +21 -0
- package/dist/test/titan-layout.js.map +1 -0
- package/dist/utils/navigation.d.ts +1 -4
- package/dist/utils/navigation.d.ts.map +1 -1
- package/dist/utils/navigation.js.map +1 -1
- package/package.json +4 -4
- package/src/components/counter-tag.tsx +1 -1
- package/src/components/profile-dropdown/interface.ts +47 -0
- package/src/components/profile-dropdown/profile-dropdown-legacy.stories.tsx +3 -3
- package/src/components/profile-dropdown/profile-dropdown-stacked.stories.tsx +3 -3
- package/src/components/profile-dropdown/profile-dropdown.stories.tsx +39 -39
- package/src/components/profile-dropdown/profile-dropdown.tsx +37 -104
- package/src/components/titan-layout/interface-internal.ts +13 -0
- package/src/components/titan-layout/interface.ts +64 -7
- package/src/components/titan-layout/layout-header-dark.tsx +21 -5
- package/src/components/titan-layout/layout-header-links-internal.tsx +41 -54
- package/src/components/titan-layout/layout-header-links.tsx +64 -8
- package/src/components/titan-layout/layout-header.module.less +37 -1
- package/src/components/titan-layout/layout-header.module.less.d.ts +3 -0
- package/src/components/titan-layout/layout-header.tsx +26 -13
- package/src/components/titan-layout/layout-profile.tsx +51 -28
- package/src/components/titan-layout/layout-sidebar-links-internal.tsx +155 -102
- package/src/components/titan-layout/layout-sidebar-links.tsx +45 -12
- package/src/components/titan-layout/layout-sidebar.module.less +74 -22
- package/src/components/titan-layout/layout-sidebar.tsx +55 -80
- package/src/components/titan-layout/{titan-layout.stories.tsx → titan-layout-default.stories.tsx} +100 -84
- package/src/components/titan-layout/titan-layout-legacy.stories.tsx +24 -0
- package/src/components/titan-layout/titan-layout-stacked.stories.tsx +30 -0
- package/src/components/titan-layout/titan-layout.tsx +67 -12
- package/src/index.ts +0 -1
- package/src/test/data.tsx +0 -165
- package/src/test/titan-layout.tsx +34 -0
- package/src/utils/navigation.ts +1 -6
- package/dist/components/titan-layout/titan-layout.stories.d.ts +0 -29
- package/dist/components/titan-layout/titan-layout.stories.d.ts.map +0 -1
- package/dist/utils/navigation-legacy.d.ts +0 -88
- package/dist/utils/navigation-legacy.d.ts.map +0 -1
- package/dist/utils/navigation-legacy.js +0 -3
- package/dist/utils/navigation-legacy.js.map +0 -1
- package/src/utils/navigation-legacy.ts +0 -106
|
@@ -3,15 +3,13 @@ import SvgExpandLess from '@servicetitan/anvil2/assets/icons/material/round/expa
|
|
|
3
3
|
import SvgExpandMore from '@servicetitan/anvil2/assets/icons/material/round/expand_more.svg';
|
|
4
4
|
import SvgAccountActive from '@servicetitan/anvil2/assets/icons/st/gnav_account_active.svg';
|
|
5
5
|
import SvgAccountInactive from '@servicetitan/anvil2/assets/icons/st/gnav_account_inactive.svg';
|
|
6
|
-
import { BodyText, Popover
|
|
6
|
+
import { BodyText, Popover } from '@servicetitan/design-system';
|
|
7
7
|
import classNames from 'classnames';
|
|
8
8
|
import {
|
|
9
9
|
ComponentPropsWithoutRef,
|
|
10
10
|
FC,
|
|
11
|
-
HTMLAttributeAnchorTarget,
|
|
12
11
|
MouseEvent,
|
|
13
12
|
MouseEventHandler,
|
|
14
|
-
ReactNode,
|
|
15
13
|
useCallback,
|
|
16
14
|
useEffect,
|
|
17
15
|
useMemo,
|
|
@@ -23,29 +21,21 @@ import { getCounterTag } from '../../utils/side-nav';
|
|
|
23
21
|
import { CounterTag } from '../counter-tag';
|
|
24
22
|
import { useTitanLayoutContext } from '../titan-layout';
|
|
25
23
|
import { withTooltip } from '../titan-layout/with-tooltip';
|
|
24
|
+
import {
|
|
25
|
+
ProfileDropdownLinkProps,
|
|
26
|
+
ProfileDropdownProps,
|
|
27
|
+
ProfileDropdownSectionProps,
|
|
28
|
+
ProfileDropdownTriggerProps,
|
|
29
|
+
} from './interface';
|
|
26
30
|
import * as Styles from './profile-dropdown.module.less';
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
open: boolean;
|
|
36
|
-
onClick?(e: MouseEvent): void;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const ProfileDropdownTrigger: FC<ProfileDropdownTriggerProps> = ({
|
|
40
|
-
avatarBadge,
|
|
41
|
-
badge,
|
|
42
|
-
className,
|
|
43
|
-
hintArrow,
|
|
44
|
-
imageSrc,
|
|
45
|
-
info,
|
|
46
|
-
onClick,
|
|
47
|
-
open,
|
|
48
|
-
}) => {
|
|
32
|
+
const ProfileDropdownTrigger: FC<
|
|
33
|
+
ProfileDropdownTriggerProps & {
|
|
34
|
+
hintArrow?: boolean;
|
|
35
|
+
open: boolean;
|
|
36
|
+
onClick: ComponentPropsWithoutRef<'div'>['onClick'];
|
|
37
|
+
}
|
|
38
|
+
> = ({ info, imageSrc, avatarBadge, badge, className, hintArrow, open, onClick, ...rest }) => {
|
|
49
39
|
const [avatarSource, setAvatarSource] = useState(imageSrc ?? '');
|
|
50
40
|
const [avatarSourceError, setAvatarSourceError] = useState(false);
|
|
51
41
|
|
|
@@ -66,6 +56,9 @@ const ProfileDropdownTrigger: FC<ProfileDropdownTriggerProps> = ({
|
|
|
66
56
|
|
|
67
57
|
return (
|
|
68
58
|
<div
|
|
59
|
+
data-cy="profile-dropdown-trigger"
|
|
60
|
+
data-pendo="profile-dropdown-trigger"
|
|
61
|
+
{...rest}
|
|
69
62
|
className={classNames(
|
|
70
63
|
'd-f align-items-center cursor-pointer position-relative p-x-1 p-y-half',
|
|
71
64
|
'profile-dropdown-trigger',
|
|
@@ -76,8 +69,6 @@ const ProfileDropdownTrigger: FC<ProfileDropdownTriggerProps> = ({
|
|
|
76
69
|
className
|
|
77
70
|
)}
|
|
78
71
|
onClick={onClick}
|
|
79
|
-
data-cy="profile-dropdown-trigger"
|
|
80
|
-
data-pendo="profile-dropdown-trigger"
|
|
81
72
|
>
|
|
82
73
|
{avatarSource && !avatarSourceError ? (
|
|
83
74
|
<img
|
|
@@ -154,25 +145,7 @@ const useTag = (counter?: CounterTagValue, tag?: CounterTagData) =>
|
|
|
154
145
|
) : undefined;
|
|
155
146
|
}, [counter, tag]);
|
|
156
147
|
|
|
157
|
-
|
|
158
|
-
| { children: string; text?: string }
|
|
159
|
-
| { children: ReactNode; text: string };
|
|
160
|
-
|
|
161
|
-
export interface ProfileDropdownSectionPropsStrict {
|
|
162
|
-
children: ReactNode;
|
|
163
|
-
id: string;
|
|
164
|
-
tooltip?: string;
|
|
165
|
-
className?: string;
|
|
166
|
-
tag?: CounterTagData;
|
|
167
|
-
counter?: CounterTagValue;
|
|
168
|
-
onClick?(e: MouseEvent): void;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export type ProfileDropdownSectionProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> &
|
|
172
|
-
ProfileDropdownSectionPropsStrict &
|
|
173
|
-
ProfileItemContent;
|
|
174
|
-
|
|
175
|
-
export const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = ({
|
|
148
|
+
function DesktopProfileDropdownSection({
|
|
176
149
|
children,
|
|
177
150
|
className,
|
|
178
151
|
counter,
|
|
@@ -182,7 +155,7 @@ export const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = ({
|
|
|
182
155
|
tooltip,
|
|
183
156
|
onClick,
|
|
184
157
|
...rest
|
|
185
|
-
})
|
|
158
|
+
}: ProfileDropdownSectionProps) {
|
|
186
159
|
const clickHandler: MouseEventHandler<never> = e => {
|
|
187
160
|
if (onClick) {
|
|
188
161
|
onClick(e);
|
|
@@ -212,27 +185,11 @@ export const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = ({
|
|
|
212
185
|
tooltip,
|
|
213
186
|
{ placement: 'left' }
|
|
214
187
|
);
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
export const ProfileDropdownDivider: FC = Popover.Divider;
|
|
218
|
-
|
|
219
|
-
export interface ProfileDropdownLinkPropsStrict {
|
|
220
|
-
id: string;
|
|
221
|
-
children: ReactNode;
|
|
222
|
-
className?: string;
|
|
223
|
-
external?: boolean;
|
|
224
|
-
target?: HTMLAttributeAnchorTarget;
|
|
225
|
-
tooltip?: string;
|
|
226
|
-
to: string;
|
|
227
|
-
tag?: CounterTagData;
|
|
228
|
-
counter?: CounterTagValue;
|
|
229
188
|
}
|
|
230
189
|
|
|
231
|
-
|
|
232
|
-
ProfileDropdownLinkPropsStrict &
|
|
233
|
-
ProfileItemContent;
|
|
190
|
+
const DesktopProfileDropdownDivider: FC = Popover.Divider;
|
|
234
191
|
|
|
235
|
-
|
|
192
|
+
function DesktopProfileDropdownLink({
|
|
236
193
|
children,
|
|
237
194
|
className,
|
|
238
195
|
external,
|
|
@@ -245,7 +202,7 @@ export const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = ({
|
|
|
245
202
|
tooltip,
|
|
246
203
|
onClick,
|
|
247
204
|
...rest
|
|
248
|
-
}: ProfileDropdownLinkProps)
|
|
205
|
+
}: ProfileDropdownLinkProps) {
|
|
249
206
|
const { NavigationComponent } = useTitanLayoutContext();
|
|
250
207
|
|
|
251
208
|
const isExternalLink = external ?? to?.startsWith('http');
|
|
@@ -291,47 +248,21 @@ export const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = ({
|
|
|
291
248
|
tooltip,
|
|
292
249
|
{ placement: 'left' }
|
|
293
250
|
);
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
export interface ProfileDropdownPropsStrict {
|
|
297
|
-
children?: ReactNode;
|
|
298
|
-
className?: string;
|
|
299
|
-
direction?: PopoverPropsStrict['direction'];
|
|
300
|
-
trigger?: Omit<ProfileDropdownTriggerProps, 'onClick' | 'open' | 'hintArrow'>;
|
|
301
|
-
hintPopup?: {
|
|
302
|
-
className?: string;
|
|
303
|
-
content: FC<{ openProfile(): void }>;
|
|
304
|
-
width?: PopoverPropsStrict['width'];
|
|
305
|
-
onClose?: () => void;
|
|
306
|
-
};
|
|
307
|
-
portal?: boolean;
|
|
308
|
-
width?: PopoverPropsStrict['width'];
|
|
309
|
-
onClose?(): void;
|
|
310
|
-
onOpen?(): void;
|
|
311
251
|
}
|
|
312
252
|
|
|
313
|
-
|
|
314
|
-
[key: string]: any;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export interface ProfileDropdownType extends FC<ProfileDropdownProps> {
|
|
318
|
-
Divider: typeof ProfileDropdownDivider;
|
|
319
|
-
Link: typeof ProfileDropdownLink;
|
|
320
|
-
Trigger: typeof ProfileDropdownTrigger;
|
|
321
|
-
Section: typeof ProfileDropdownSection;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export const ProfileDropdown: ProfileDropdownType = (({
|
|
253
|
+
function DesktopProfileDropdownComponent({
|
|
325
254
|
children,
|
|
326
|
-
|
|
255
|
+
|
|
327
256
|
direction,
|
|
257
|
+
trigger,
|
|
328
258
|
hintPopup,
|
|
329
|
-
onClose,
|
|
330
|
-
onOpen,
|
|
331
259
|
portal,
|
|
332
|
-
trigger,
|
|
333
260
|
width,
|
|
334
|
-
|
|
261
|
+
onClose,
|
|
262
|
+
onOpen,
|
|
263
|
+
|
|
264
|
+
...rest
|
|
265
|
+
}: ProfileDropdownProps) {
|
|
335
266
|
const [open, setOpen] = useState(false);
|
|
336
267
|
const handleClose = useCallback(() => {
|
|
337
268
|
setOpen(false);
|
|
@@ -367,7 +298,7 @@ export const ProfileDropdown: ProfileDropdownType = (({
|
|
|
367
298
|
);
|
|
368
299
|
|
|
369
300
|
return (
|
|
370
|
-
<div
|
|
301
|
+
<div data-cy="profile-dropdown" {...rest}>
|
|
371
302
|
{!!hintPopup && hintShown && HintComponent ? (
|
|
372
303
|
<Popover
|
|
373
304
|
direction={direction ?? 'bl'}
|
|
@@ -406,8 +337,10 @@ export const ProfileDropdown: ProfileDropdownType = (({
|
|
|
406
337
|
)}
|
|
407
338
|
</div>
|
|
408
339
|
);
|
|
409
|
-
}
|
|
340
|
+
}
|
|
410
341
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
342
|
+
export const DesktopProfileDropdown = Object.assign(DesktopProfileDropdownComponent, {
|
|
343
|
+
Divider: DesktopProfileDropdownDivider,
|
|
344
|
+
Link: DesktopProfileDropdownLink,
|
|
345
|
+
Section: DesktopProfileDropdownSection,
|
|
346
|
+
});
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
import { IconProps } from '@servicetitan/anvil2';
|
|
1
2
|
import { FC } from 'react';
|
|
3
|
+
import { CounterTagData } from '../../utils/counter-tag';
|
|
2
4
|
import { NavLinkComponentProps } from '../../utils/navigation-context';
|
|
3
5
|
|
|
4
6
|
export interface NavigationComponentProps {
|
|
5
7
|
navigationComponent: FC<NavLinkComponentProps>;
|
|
6
8
|
}
|
|
9
|
+
export interface NavigationItemPropsStrict {
|
|
10
|
+
id: string;
|
|
11
|
+
to: string;
|
|
12
|
+
title: string;
|
|
13
|
+
isActive: boolean | ((pathname: string) => boolean) | undefined;
|
|
14
|
+
icon: IconProps['svg'] | undefined;
|
|
15
|
+
iconActive: IconProps['svg'] | undefined;
|
|
16
|
+
|
|
17
|
+
tag: CounterTagData | undefined;
|
|
18
|
+
className: string | undefined;
|
|
19
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { IconProps } from '@servicetitan/anvil2';
|
|
1
2
|
import { ComponentPropsWithoutRef, FC, ReactNode } from 'react';
|
|
2
|
-
import {
|
|
3
|
+
import { CounterTagData, CounterTagValue } from '../../utils/counter-tag';
|
|
3
4
|
import { TitanLayoutSidebarContextType } from './layout-context';
|
|
4
5
|
|
|
5
6
|
export interface TitanLayoutLinkWrapperProps {
|
|
@@ -11,20 +12,76 @@ export interface TitanLayoutLinkWrapperProps {
|
|
|
11
12
|
export type TitanLayoutLinkWrapper = FC<TitanLayoutLinkWrapperProps>;
|
|
12
13
|
|
|
13
14
|
export interface TitanLayoutState {
|
|
15
|
+
/** flags if side nav is collapsed */
|
|
14
16
|
navCollapsed: boolean;
|
|
15
|
-
|
|
17
|
+
/** ;ost expanded submenu ids */
|
|
18
|
+
submenusExpanded?: string[];
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
export
|
|
21
|
+
export interface TitanLayoutLinkExtraProps {
|
|
22
|
+
/** link's title should be shown (for extra links we show icon only by default) */
|
|
23
|
+
showTitle?: boolean;
|
|
24
|
+
/** link is flashing */
|
|
25
|
+
flashing?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TitanLayoutLinkSideProps {
|
|
29
|
+
/** counter value used only for side links */
|
|
30
|
+
counter: CounterTagValue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type TitanLayoutLinkProps = {
|
|
34
|
+
/** link id */
|
|
35
|
+
id: string;
|
|
36
|
+
/** link href */
|
|
37
|
+
to: string;
|
|
38
|
+
/** link title */
|
|
39
|
+
title: string;
|
|
40
|
+
/** callback to return active state. By default, it compares link href with current pathname */
|
|
41
|
+
isActive?: boolean | ((pathname: string) => boolean);
|
|
42
|
+
/** svg icon (anvil2) of inactive item */
|
|
43
|
+
icon: IconProps['svg'] | undefined;
|
|
44
|
+
/** svg icon (anvil2) of active item */
|
|
45
|
+
iconActive: IconProps['svg'] | undefined;
|
|
46
|
+
/** item tag (optional). shown if it is set and value is true or greater than 0 */
|
|
47
|
+
tag?: CounterTagData;
|
|
48
|
+
counter?: CounterTagValue;
|
|
49
|
+
/** class name of link item */
|
|
50
|
+
className?: string;
|
|
51
|
+
|
|
52
|
+
/** tooltip text (for extra links) */
|
|
19
53
|
tooltip?: string;
|
|
54
|
+
/** wrapper component for link element (used for side links) */
|
|
20
55
|
wrapper?: TitanLayoutLinkWrapper;
|
|
56
|
+
/** props for extra link element */
|
|
57
|
+
extra?: TitanLayoutLinkExtraProps;
|
|
58
|
+
/** props for side nav link element (mobile version) */
|
|
59
|
+
side?: TitanLayoutLinkSideProps;
|
|
21
60
|
} & Omit<ComponentPropsWithoutRef<'a'>, 'children' | 'title'>;
|
|
22
61
|
|
|
23
|
-
export type TitanLayoutTriggerProps =
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
62
|
+
export type TitanLayoutTriggerProps = {
|
|
63
|
+
/** link id */
|
|
64
|
+
id: string;
|
|
65
|
+
/** link title */
|
|
66
|
+
title: string;
|
|
67
|
+
/** active state */
|
|
27
68
|
isActive?: boolean;
|
|
69
|
+
/** svg icon (anvil2) of inactive item */
|
|
70
|
+
icon: IconProps['svg'] | undefined;
|
|
71
|
+
/** svg icon (anvil2) of active item */
|
|
72
|
+
iconActive: IconProps['svg'] | undefined;
|
|
73
|
+
/** item tag (optional). shown if it is set and value is true or greater than 0 */
|
|
74
|
+
tag?: CounterTagData;
|
|
75
|
+
counter?: CounterTagValue;
|
|
76
|
+
/** class name of link item */
|
|
77
|
+
className?: string;
|
|
78
|
+
|
|
79
|
+
/** tooltip text (for extra links) */
|
|
28
80
|
tooltip?: string;
|
|
81
|
+
/** wrapper component for link element (used for side links) */
|
|
29
82
|
wrapper?: TitanLayoutLinkWrapper;
|
|
83
|
+
/** props for extra link element */
|
|
84
|
+
extra?: TitanLayoutLinkExtraProps;
|
|
85
|
+
/** props for nav link element (mobile version) */
|
|
86
|
+
side?: TitanLayoutLinkSideProps;
|
|
30
87
|
} & Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'title'>;
|
|
@@ -3,6 +3,7 @@ import SvgMoreVert from '@servicetitan/anvil2/assets/icons/material/round/more_v
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
|
5
5
|
import { NavigationItemData } from '../../utils/navigation';
|
|
6
|
+
import { getCounterTag } from '../../utils/side-nav';
|
|
6
7
|
import { NavigationComponentProps } from './interface-internal';
|
|
7
8
|
import { useTitanLayoutContext } from './layout-context';
|
|
8
9
|
import { LayoutHeader, LayoutHeaderProps } from './layout-header';
|
|
@@ -34,7 +35,6 @@ export const LayoutHeaderDark: FC<LayoutHeaderStackedProps> = ({
|
|
|
34
35
|
navigationMainItems,
|
|
35
36
|
navigationOverflowItems,
|
|
36
37
|
hasNotifications,
|
|
37
|
-
onBurgerClick,
|
|
38
38
|
logo,
|
|
39
39
|
profile,
|
|
40
40
|
right,
|
|
@@ -42,6 +42,8 @@ export const LayoutHeaderDark: FC<LayoutHeaderStackedProps> = ({
|
|
|
42
42
|
rightClassName,
|
|
43
43
|
center,
|
|
44
44
|
centerClassName,
|
|
45
|
+
hasBurger,
|
|
46
|
+
onBurgerClick,
|
|
45
47
|
...rest
|
|
46
48
|
}) => {
|
|
47
49
|
return center ? (
|
|
@@ -62,6 +64,7 @@ export const LayoutHeaderDark: FC<LayoutHeaderStackedProps> = ({
|
|
|
62
64
|
logo={logo}
|
|
63
65
|
profile={profile}
|
|
64
66
|
onBurgerClick={onBurgerClick}
|
|
67
|
+
hasBurger={hasBurger}
|
|
65
68
|
data-cy="header-navigation-top"
|
|
66
69
|
/>
|
|
67
70
|
|
|
@@ -94,6 +97,7 @@ export const LayoutHeaderDark: FC<LayoutHeaderStackedProps> = ({
|
|
|
94
97
|
logo={logo}
|
|
95
98
|
profile={profile}
|
|
96
99
|
onBurgerClick={onBurgerClick}
|
|
100
|
+
hasBurger={hasBurger}
|
|
97
101
|
{...rest}
|
|
98
102
|
/>
|
|
99
103
|
);
|
|
@@ -155,8 +159,14 @@ const LayoutHeaderNav: FC<LayoutHeaderNavProps> = ({ className, mainItems, overf
|
|
|
155
159
|
{mainItems?.map(item =>
|
|
156
160
|
withTooltip(
|
|
157
161
|
<InternalLayoutHeaderNavigationLink
|
|
158
|
-
{
|
|
159
|
-
|
|
162
|
+
id={item.id}
|
|
163
|
+
to={item.to}
|
|
164
|
+
title={isMinimized ? undefined : item.title}
|
|
165
|
+
isActive={item.isActive}
|
|
166
|
+
icon={item.icon}
|
|
167
|
+
iconActive={item.iconActive}
|
|
168
|
+
tag={getCounterTag(item.counter, item.tag)}
|
|
169
|
+
className={item.className}
|
|
160
170
|
key={item.id}
|
|
161
171
|
navigationComponent={NavigationComponent}
|
|
162
172
|
/>,
|
|
@@ -195,8 +205,14 @@ const LayoutHeaderNavOverflow: FC<
|
|
|
195
205
|
<div data-cy="navigation-overflow-content" className={Styles.headerNavigationOverflow}>
|
|
196
206
|
{items.map(item => (
|
|
197
207
|
<InternalLayoutHeaderNavigationLink
|
|
198
|
-
{
|
|
199
|
-
|
|
208
|
+
id={item.id}
|
|
209
|
+
to={item.to}
|
|
210
|
+
title={item.title}
|
|
211
|
+
isActive={item.isActive}
|
|
212
|
+
icon={item.icon}
|
|
213
|
+
iconActive={item.iconActive}
|
|
214
|
+
tag={getCounterTag(item.counter, item.tag)}
|
|
215
|
+
className={item.className}
|
|
200
216
|
key={item.id}
|
|
201
217
|
navigationComponent={navigationComponent}
|
|
202
218
|
isOverflow
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { Icon, IconProps } from '@servicetitan/anvil2';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { FC, Fragment } from 'react';
|
|
4
|
-
import {
|
|
5
|
-
HeaderNavigationLinkProps,
|
|
6
|
-
HeaderNavigationTriggerProps,
|
|
7
|
-
} from '../../utils/navigation-legacy';
|
|
8
|
-
import { getCounterTag } from '../../utils/side-nav';
|
|
4
|
+
import { CounterTagData } from '../../utils/counter-tag';
|
|
9
5
|
import { CounterTag, CounterTagProps } from '../counter-tag';
|
|
10
|
-
// use v1 tooltips due to bug with v2 in monolith
|
|
11
6
|
import { NavigationComponentProps } from './interface-internal';
|
|
12
7
|
import * as Styles from './layout-header.module.less';
|
|
13
8
|
|
|
@@ -17,9 +12,8 @@ const InternalHeaderNavigationItemContent: FC<{
|
|
|
17
12
|
counterClassName?: string;
|
|
18
13
|
icon: IconProps['svg'] | undefined;
|
|
19
14
|
iconActive?: IconProps['svg'];
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}> = ({ counterClassName, icon, iconActive, label, labelClassName, tag }) => {
|
|
15
|
+
title?: string;
|
|
16
|
+
}> = ({ counterClassName, icon, iconActive, title, tag }) => {
|
|
23
17
|
return (
|
|
24
18
|
<Fragment>
|
|
25
19
|
{!!icon && <Icon svg={icon} className={Styles.navigationIcon} />}
|
|
@@ -30,12 +24,9 @@ const InternalHeaderNavigationItemContent: FC<{
|
|
|
30
24
|
/>
|
|
31
25
|
)}
|
|
32
26
|
|
|
33
|
-
{!!
|
|
34
|
-
<span
|
|
35
|
-
|
|
36
|
-
data-cy="nav-item-label"
|
|
37
|
-
>
|
|
38
|
-
{label}
|
|
27
|
+
{!!title && (
|
|
28
|
+
<span className={Styles.navigationItemLabel} data-cy="nav-item-label">
|
|
29
|
+
{title}
|
|
39
30
|
</span>
|
|
40
31
|
)}
|
|
41
32
|
|
|
@@ -52,26 +43,30 @@ const InternalHeaderNavigationItemContent: FC<{
|
|
|
52
43
|
|
|
53
44
|
/** Navigation extra item with link */
|
|
54
45
|
export const InternalLayoutHeaderNavigationLink: FC<
|
|
55
|
-
|
|
46
|
+
NavigationComponentProps & {
|
|
47
|
+
id: string;
|
|
48
|
+
to: string;
|
|
49
|
+
title: string | undefined;
|
|
50
|
+
isActive: boolean | ((pathname: string) => boolean) | undefined;
|
|
51
|
+
icon: IconProps['svg'] | undefined;
|
|
52
|
+
iconActive: IconProps['svg'] | undefined;
|
|
53
|
+
tag: CounterTagData | undefined;
|
|
54
|
+
className: string | undefined;
|
|
55
|
+
|
|
56
|
+
isOverflow?: boolean;
|
|
57
|
+
flashing?: boolean;
|
|
58
|
+
}
|
|
56
59
|
> = ({
|
|
57
60
|
id,
|
|
58
61
|
to,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
className,
|
|
62
|
-
counter,
|
|
62
|
+
title,
|
|
63
|
+
isActive,
|
|
63
64
|
icon,
|
|
64
65
|
iconActive,
|
|
65
|
-
iconClassName,
|
|
66
|
-
iconName,
|
|
67
|
-
iconComponent,
|
|
68
|
-
isActive,
|
|
69
|
-
isOverflow,
|
|
70
|
-
label,
|
|
71
|
-
labelClassName,
|
|
72
66
|
tag,
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
className,
|
|
68
|
+
isOverflow,
|
|
69
|
+
flashing,
|
|
75
70
|
navigationComponent: NavigationComponent,
|
|
76
71
|
...rest
|
|
77
72
|
}) => {
|
|
@@ -88,63 +83,55 @@ export const InternalLayoutHeaderNavigationLink: FC<
|
|
|
88
83
|
{
|
|
89
84
|
[Styles.navigationItemActive]: isActive === true,
|
|
90
85
|
[Styles.navigationItemIconState]: !!icon && !!iconActive,
|
|
86
|
+
[Styles.navigationItemFlashing]: flashing,
|
|
91
87
|
}
|
|
92
88
|
)}
|
|
93
89
|
isActive={typeof isActive === 'function' ? isActive : undefined}
|
|
94
90
|
activeClassName={Styles.navigationItemActive}
|
|
95
|
-
target={target}
|
|
96
91
|
>
|
|
97
92
|
<InternalHeaderNavigationItemContent
|
|
98
|
-
tag={
|
|
93
|
+
tag={tag}
|
|
99
94
|
icon={icon}
|
|
100
95
|
iconActive={iconActive}
|
|
101
|
-
|
|
102
|
-
labelClassName={labelClassName}
|
|
96
|
+
title={title}
|
|
103
97
|
/>
|
|
104
98
|
</NavigationComponent>
|
|
105
99
|
);
|
|
106
100
|
};
|
|
107
101
|
|
|
108
102
|
/** Navigation extra item with icon button */
|
|
109
|
-
export const InternalLayoutHeaderNavigationTrigger: FC<
|
|
110
|
-
id
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
icon
|
|
114
|
-
iconActive
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
tag,
|
|
121
|
-
tooltip,
|
|
122
|
-
title,
|
|
123
|
-
titleClassName,
|
|
124
|
-
...rest
|
|
125
|
-
}) => {
|
|
103
|
+
export const InternalLayoutHeaderNavigationTrigger: FC<{
|
|
104
|
+
id: string;
|
|
105
|
+
title: string | undefined;
|
|
106
|
+
isActive: boolean | undefined;
|
|
107
|
+
icon: IconProps['svg'] | undefined;
|
|
108
|
+
iconActive: IconProps['svg'] | undefined;
|
|
109
|
+
tag: CounterTagData | undefined;
|
|
110
|
+
className: string | undefined;
|
|
111
|
+
|
|
112
|
+
flashing?: boolean;
|
|
113
|
+
}> = ({ id, className, flashing, icon, iconActive, isActive, tag, title, ...rest }) => {
|
|
126
114
|
return (
|
|
127
115
|
<div
|
|
128
116
|
data-cy={`navigation-trigger-${id}`}
|
|
129
117
|
data-pendo={`navigation-trigger-${id}`}
|
|
130
118
|
{...rest}
|
|
131
|
-
title={hint}
|
|
132
119
|
className={classNames(
|
|
133
120
|
Styles.navigationLink,
|
|
134
121
|
{
|
|
135
122
|
[Styles.navigationItemActive]: isActive === true,
|
|
136
123
|
[Styles.navigationItemIconState]: !!icon && !!iconActive,
|
|
124
|
+
[Styles.navigationItemFlashing]: flashing,
|
|
137
125
|
},
|
|
138
126
|
'cursor-pointer',
|
|
139
127
|
className
|
|
140
128
|
)}
|
|
141
129
|
>
|
|
142
130
|
<InternalHeaderNavigationItemContent
|
|
143
|
-
tag={
|
|
131
|
+
tag={tag}
|
|
144
132
|
icon={icon}
|
|
145
133
|
iconActive={iconActive}
|
|
146
|
-
|
|
147
|
-
labelClassName={labelClassName}
|
|
134
|
+
title={title}
|
|
148
135
|
/>
|
|
149
136
|
</div>
|
|
150
137
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCounterTag } from '../../utils/side-nav';
|
|
2
2
|
import { TitanLayoutLinkProps, TitanLayoutTriggerProps } from './interface';
|
|
3
3
|
import { useTitanLayoutContext } from './layout-context';
|
|
4
4
|
import {
|
|
@@ -8,19 +8,75 @@ import {
|
|
|
8
8
|
import { withTooltip } from './with-tooltip';
|
|
9
9
|
|
|
10
10
|
/** Navigation extra item with link */
|
|
11
|
-
export
|
|
11
|
+
export function LayoutHeaderNavigationLink({
|
|
12
|
+
id,
|
|
13
|
+
to,
|
|
14
|
+
title,
|
|
15
|
+
isActive,
|
|
16
|
+
icon,
|
|
17
|
+
iconActive,
|
|
18
|
+
counter,
|
|
19
|
+
tag,
|
|
20
|
+
className,
|
|
21
|
+
|
|
22
|
+
tooltip,
|
|
23
|
+
extra,
|
|
24
|
+
side,
|
|
25
|
+
wrapper,
|
|
26
|
+
...rest
|
|
27
|
+
}: TitanLayoutLinkProps) {
|
|
12
28
|
const { NavigationComponent } = useTitanLayoutContext();
|
|
29
|
+
const { showTitle, flashing } = extra ?? {};
|
|
13
30
|
|
|
14
31
|
return withTooltip(
|
|
15
|
-
<InternalLayoutHeaderNavigationLink
|
|
32
|
+
<InternalLayoutHeaderNavigationLink
|
|
33
|
+
id={id}
|
|
34
|
+
to={to}
|
|
35
|
+
title={showTitle ? title : undefined}
|
|
36
|
+
isActive={isActive}
|
|
37
|
+
icon={icon}
|
|
38
|
+
iconActive={iconActive}
|
|
39
|
+
tag={getCounterTag(counter, tag)}
|
|
40
|
+
className={className}
|
|
41
|
+
{...rest}
|
|
42
|
+
flashing={flashing}
|
|
43
|
+
navigationComponent={NavigationComponent}
|
|
44
|
+
/>,
|
|
16
45
|
tooltip
|
|
17
46
|
);
|
|
18
|
-
}
|
|
47
|
+
}
|
|
19
48
|
|
|
20
49
|
/** Navigation extra item with icon button */
|
|
21
|
-
export
|
|
50
|
+
export function LayoutHeaderNavigationTrigger({
|
|
51
|
+
id,
|
|
52
|
+
title,
|
|
53
|
+
isActive,
|
|
54
|
+
icon,
|
|
55
|
+
iconActive,
|
|
56
|
+
counter,
|
|
57
|
+
tag,
|
|
58
|
+
className,
|
|
59
|
+
|
|
22
60
|
tooltip,
|
|
61
|
+
extra,
|
|
62
|
+
side,
|
|
63
|
+
wrapper,
|
|
23
64
|
...rest
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
|
|
65
|
+
}: TitanLayoutTriggerProps) {
|
|
66
|
+
const { showTitle, flashing } = extra ?? {};
|
|
67
|
+
|
|
68
|
+
return withTooltip(
|
|
69
|
+
<InternalLayoutHeaderNavigationTrigger
|
|
70
|
+
id={id}
|
|
71
|
+
title={showTitle ? title : undefined}
|
|
72
|
+
isActive={isActive}
|
|
73
|
+
icon={icon}
|
|
74
|
+
iconActive={iconActive}
|
|
75
|
+
tag={getCounterTag(counter, tag)}
|
|
76
|
+
className={className}
|
|
77
|
+
{...rest}
|
|
78
|
+
flashing={flashing}
|
|
79
|
+
/>,
|
|
80
|
+
tooltip
|
|
81
|
+
);
|
|
82
|
+
}
|