@servicetitan/navigation 14.2.0 → 14.3.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/titan-layout/__tests__/layout-sidebar-links-internal.test.d.ts +2 -0
- package/dist/components/titan-layout/__tests__/layout-sidebar-links-internal.test.d.ts.map +1 -0
- package/dist/components/titan-layout/__tests__/navigation-catalog-reset.test.d.ts +2 -0
- package/dist/components/titan-layout/__tests__/navigation-catalog-reset.test.d.ts.map +1 -0
- package/dist/components/titan-layout/interface.d.ts +66 -0
- 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-sidebar-links-internal.d.ts +3 -0
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.js +58 -13
- package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.d.ts +14 -0
- package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.js +169 -97
- package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +230 -144
- package/dist/components/titan-layout/layout-sidebar.module.less.d.ts +16 -5
- package/dist/components/titan-layout/navigation-catalog/index.d.ts +3 -0
- package/dist/components/titan-layout/navigation-catalog/index.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/index.js +4 -0
- package/dist/components/titan-layout/navigation-catalog/index.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.d.ts +8 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.js +88 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.d.ts +21 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.js +138 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less +89 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less.d.ts +9 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.d.ts +14 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.js +382 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.module.less +436 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.module.less.d.ts +24 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.d.ts +12 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.js +48 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.js.map +1 -0
- package/dist/components/titan-layout/titan-layout.d.ts +29 -1
- package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.js +46 -6
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/components/titan-layout/titan-layout.module.less +2 -1
- package/dist/components/titan-layout/use-navigation-scroll.d.ts +20 -0
- package/dist/components/titan-layout/use-navigation-scroll.d.ts.map +1 -0
- package/dist/components/titan-layout/use-navigation-scroll.js +140 -0
- package/dist/components/titan-layout/use-navigation-scroll.js.map +1 -0
- package/dist/utils/__tests__/navigation-notifications.test.d.ts +2 -0
- package/dist/utils/__tests__/navigation-notifications.test.d.ts.map +1 -0
- package/dist/utils/__tests__/submenu-state.test.d.ts +2 -0
- package/dist/utils/__tests__/submenu-state.test.d.ts.map +1 -0
- package/dist/utils/navigation-notifications.d.ts +21 -0
- package/dist/utils/navigation-notifications.d.ts.map +1 -0
- package/dist/utils/navigation-notifications.js +39 -0
- package/dist/utils/navigation-notifications.js.map +1 -0
- package/dist/utils/side-nav.js +3 -1
- package/dist/utils/side-nav.js.map +1 -1
- package/dist/utils/submenu-state.d.ts +3 -0
- package/dist/utils/submenu-state.d.ts.map +1 -0
- package/dist/utils/submenu-state.js +15 -0
- package/dist/utils/submenu-state.js.map +1 -0
- package/package.json +2 -2
- package/src/components/titan-layout/__tests__/layout-sidebar-links-internal.test.tsx +225 -0
- package/src/components/titan-layout/__tests__/navigation-catalog-reset.test.tsx +186 -0
- package/src/components/titan-layout/interface.ts +73 -0
- package/src/components/titan-layout/layout-sidebar-links-internal.tsx +86 -14
- package/src/components/titan-layout/layout-sidebar.module.less +230 -144
- package/src/components/titan-layout/layout-sidebar.module.less.d.ts +16 -5
- package/src/components/titan-layout/layout-sidebar.tsx +193 -117
- package/src/components/titan-layout/navigation-catalog/index.ts +2 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-footer.tsx +88 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less +89 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less.d.ts +9 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.tsx +170 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.module.less +436 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.module.less.d.ts +24 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.tsx +458 -0
- package/src/components/titan-layout/navigation-scroll-indicators.tsx +80 -0
- package/src/components/titan-layout/titan-layout.module.less +2 -1
- package/src/components/titan-layout/titan-layout.tsx +81 -5
- package/src/components/titan-layout/use-navigation-scroll.ts +145 -0
- package/src/utils/__tests__/navigation-notifications.test.ts +70 -0
- package/src/utils/__tests__/submenu-state.test.ts +39 -0
- package/src/utils/navigation-notifications.ts +59 -0
- package/src/utils/side-nav.ts +1 -1
- package/src/utils/submenu-state.ts +16 -0
|
@@ -2,7 +2,16 @@ import { Button, Icon, IconProps } from '@servicetitan/anvil2';
|
|
|
2
2
|
import SvgGroupCollapse from '@servicetitan/anvil2/assets/icons/material/round/expand_less.svg';
|
|
3
3
|
import SvgGroupExpand from '@servicetitan/anvil2/assets/icons/material/round/expand_more.svg';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ComponentPropsWithoutRef,
|
|
7
|
+
FC,
|
|
8
|
+
Fragment,
|
|
9
|
+
MouseEvent,
|
|
10
|
+
ReactNode,
|
|
11
|
+
SyntheticEvent,
|
|
12
|
+
useId,
|
|
13
|
+
} from 'react';
|
|
14
|
+
import { getNotificationCount } from '../../utils/navigation-notifications';
|
|
6
15
|
|
|
7
16
|
import { BadgeTag, BadgeTagProps } from '../badge-tag';
|
|
8
17
|
import { NavigationComponentProps } from './interface-internal';
|
|
@@ -46,12 +55,7 @@ const InternalSideNavigationItemContent: FC<InternalSideNavigationItemContentPro
|
|
|
46
55
|
)}
|
|
47
56
|
</div>
|
|
48
57
|
|
|
49
|
-
<div
|
|
50
|
-
className={classNames(Styles.navItemTextCollapsed, {
|
|
51
|
-
[Styles.navItemTextSmall]: !!title && title.length >= 10,
|
|
52
|
-
})}
|
|
53
|
-
data-cy="nav-item-label"
|
|
54
|
-
>
|
|
58
|
+
<div className={Styles.navItemTextCollapsed} data-cy="nav-item-label">
|
|
55
59
|
{title}
|
|
56
60
|
</div>
|
|
57
61
|
</Fragment>
|
|
@@ -68,6 +72,7 @@ export const InternalSideNavigationLink: FC<
|
|
|
68
72
|
iconActive: IconProps['svg'] | undefined;
|
|
69
73
|
className: string | undefined;
|
|
70
74
|
tag: BadgeTagProps | undefined;
|
|
75
|
+
notificationCount?: number;
|
|
71
76
|
} & Omit<ComponentPropsWithoutRef<'a'>, 'children' | 'title'>
|
|
72
77
|
> = ({
|
|
73
78
|
id,
|
|
@@ -78,6 +83,7 @@ export const InternalSideNavigationLink: FC<
|
|
|
78
83
|
iconActive,
|
|
79
84
|
className,
|
|
80
85
|
tag,
|
|
86
|
+
notificationCount = getNotificationCount(tag?.value),
|
|
81
87
|
|
|
82
88
|
navigationComponent: NavigationComponent,
|
|
83
89
|
...rest
|
|
@@ -86,6 +92,7 @@ export const InternalSideNavigationLink: FC<
|
|
|
86
92
|
<NavigationComponent
|
|
87
93
|
data-cy={`navigation-item-${id}`}
|
|
88
94
|
data-pendo={`navigation-item-${id}`}
|
|
95
|
+
data-navigation-notification-count={notificationCount || undefined}
|
|
89
96
|
{...rest}
|
|
90
97
|
className={classNames(Styles.navItem, Styles.navLink, className, {
|
|
91
98
|
[Styles.navItemActive]: isActive === true,
|
|
@@ -117,6 +124,7 @@ export const InternalSideNavigationTrigger: FC<
|
|
|
117
124
|
className: string | undefined;
|
|
118
125
|
|
|
119
126
|
tag: BadgeTagProps | undefined;
|
|
127
|
+
notificationCount?: number;
|
|
120
128
|
onClick?: (e: MouseEvent<never>) => void;
|
|
121
129
|
} & Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'title'>
|
|
122
130
|
> = ({
|
|
@@ -128,12 +136,14 @@ export const InternalSideNavigationTrigger: FC<
|
|
|
128
136
|
className,
|
|
129
137
|
|
|
130
138
|
tag,
|
|
139
|
+
notificationCount = getNotificationCount(tag?.value),
|
|
131
140
|
...rest
|
|
132
141
|
}) => {
|
|
133
142
|
return (
|
|
134
143
|
<div
|
|
135
144
|
data-cy={`navigation-item-${id}`}
|
|
136
145
|
data-pendo={`navigation-item-${id}`}
|
|
146
|
+
data-navigation-notification-count={notificationCount || undefined}
|
|
137
147
|
tabIndex={rest.onClick ? 0 : -1}
|
|
138
148
|
{...rest}
|
|
139
149
|
className={classNames(Styles.navItem, className, {
|
|
@@ -186,6 +196,7 @@ export const InternalSideNavigationGroupLink: FC<
|
|
|
186
196
|
key={id}
|
|
187
197
|
data-cy={`navigation-item-${parentId}--${id}`}
|
|
188
198
|
data-pendo={`navigation-item-${parentId}--${id}`}
|
|
199
|
+
data-navigation-notification-count={getNotificationCount(tag?.value) || undefined}
|
|
189
200
|
{...rest}
|
|
190
201
|
to={to}
|
|
191
202
|
className={classNames(Styles.submenuItem, Styles.submenuLink, className, {
|
|
@@ -221,6 +232,7 @@ export const InternalSideNavigationGroupTrigger: FC<{
|
|
|
221
232
|
return (
|
|
222
233
|
<div
|
|
223
234
|
data-cy={`navigation-item-${id}`}
|
|
235
|
+
data-navigation-notification-count={getNotificationCount(tag?.value) || undefined}
|
|
224
236
|
data-pendo={`navigation-item-${id}`}
|
|
225
237
|
key={id}
|
|
226
238
|
{...rest}
|
|
@@ -250,6 +262,7 @@ export const InternalSideNavigationGroup: FC<
|
|
|
250
262
|
className: string | undefined;
|
|
251
263
|
tag: BadgeTagProps | undefined;
|
|
252
264
|
|
|
265
|
+
notificationCount?: number;
|
|
253
266
|
children: ReactNode;
|
|
254
267
|
submenuOpened: boolean;
|
|
255
268
|
onClick?: (e: MouseEvent<never>) => void;
|
|
@@ -265,6 +278,7 @@ export const InternalSideNavigationGroup: FC<
|
|
|
265
278
|
className,
|
|
266
279
|
tag,
|
|
267
280
|
|
|
281
|
+
notificationCount,
|
|
268
282
|
children,
|
|
269
283
|
submenuOpened,
|
|
270
284
|
onSubmenuOpen,
|
|
@@ -272,16 +286,62 @@ export const InternalSideNavigationGroup: FC<
|
|
|
272
286
|
navigationComponent,
|
|
273
287
|
...rest
|
|
274
288
|
}) => {
|
|
275
|
-
const
|
|
276
|
-
|
|
289
|
+
const submenuId = useId();
|
|
290
|
+
const onToggleClick = (e: SyntheticEvent) => {
|
|
277
291
|
e.preventDefault();
|
|
278
292
|
e.stopPropagation();
|
|
293
|
+
onSubmenuOpen(id, !submenuOpened);
|
|
279
294
|
};
|
|
280
295
|
|
|
281
296
|
return (
|
|
282
|
-
<div
|
|
297
|
+
<div
|
|
298
|
+
className={classNames(Styles.navGroupWrapper, {
|
|
299
|
+
[Styles.navGroupOpened]: submenuOpened,
|
|
300
|
+
})}
|
|
301
|
+
>
|
|
283
302
|
<div className={Styles.navGroupItem}>
|
|
284
|
-
<div
|
|
303
|
+
<div
|
|
304
|
+
// Update expansion before the host link handles navigation to its destination.
|
|
305
|
+
onClickCapture={event => {
|
|
306
|
+
if (!to) {
|
|
307
|
+
onToggleClick(event);
|
|
308
|
+
} else if (
|
|
309
|
+
/*
|
|
310
|
+
* A module name only ever opens. It navigates into the module, so
|
|
311
|
+
* collapsing would hide the very page the click is about to land on —
|
|
312
|
+
* the destination is `to`, whether that is a page itself or an entry
|
|
313
|
+
* route the host redirects to the module's default page. Collapsing an
|
|
314
|
+
* open module is the chevron's job.
|
|
315
|
+
*/
|
|
316
|
+
!submenuOpened &&
|
|
317
|
+
event.button === 0 &&
|
|
318
|
+
!event.altKey &&
|
|
319
|
+
!event.ctrlKey &&
|
|
320
|
+
!event.metaKey &&
|
|
321
|
+
!event.shiftKey
|
|
322
|
+
) {
|
|
323
|
+
onSubmenuOpen(id, true);
|
|
324
|
+
}
|
|
325
|
+
}}
|
|
326
|
+
onClick={event => event.stopPropagation()}
|
|
327
|
+
onKeyDownCapture={event => {
|
|
328
|
+
if (
|
|
329
|
+
(event.key === 'Enter' || event.key === ' ') &&
|
|
330
|
+
!event.altKey &&
|
|
331
|
+
!event.ctrlKey &&
|
|
332
|
+
!event.metaKey &&
|
|
333
|
+
!event.shiftKey
|
|
334
|
+
) {
|
|
335
|
+
if (to) {
|
|
336
|
+
event.preventDefault();
|
|
337
|
+
event.stopPropagation();
|
|
338
|
+
event.currentTarget.querySelector('a')?.click();
|
|
339
|
+
} else {
|
|
340
|
+
onToggleClick(event);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}}
|
|
344
|
+
>
|
|
285
345
|
{to ? (
|
|
286
346
|
<InternalSideNavigationLink
|
|
287
347
|
id={id}
|
|
@@ -291,8 +351,11 @@ export const InternalSideNavigationGroup: FC<
|
|
|
291
351
|
icon={icon}
|
|
292
352
|
iconActive={iconActive}
|
|
293
353
|
tag={tag}
|
|
354
|
+
notificationCount={notificationCount}
|
|
294
355
|
className={className}
|
|
295
356
|
{...rest}
|
|
357
|
+
aria-expanded={submenuOpened}
|
|
358
|
+
aria-controls={submenuId}
|
|
296
359
|
navigationComponent={navigationComponent}
|
|
297
360
|
/>
|
|
298
361
|
) : (
|
|
@@ -303,8 +366,14 @@ export const InternalSideNavigationGroup: FC<
|
|
|
303
366
|
icon={icon}
|
|
304
367
|
iconActive={iconActive}
|
|
305
368
|
tag={tag}
|
|
369
|
+
notificationCount={notificationCount}
|
|
306
370
|
className={className}
|
|
307
371
|
{...rest}
|
|
372
|
+
role="button"
|
|
373
|
+
tabIndex={0}
|
|
374
|
+
onClick={onToggleClick}
|
|
375
|
+
aria-expanded={submenuOpened}
|
|
376
|
+
aria-controls={submenuId}
|
|
308
377
|
/>
|
|
309
378
|
)}
|
|
310
379
|
</div>
|
|
@@ -312,12 +381,14 @@ export const InternalSideNavigationGroup: FC<
|
|
|
312
381
|
<div className={Styles.navItemGroupToggleWrapper}>
|
|
313
382
|
{withTooltip(
|
|
314
383
|
<Button
|
|
315
|
-
appearance="
|
|
316
|
-
size="
|
|
384
|
+
appearance="ghost"
|
|
385
|
+
size="xsmall"
|
|
317
386
|
icon={submenuOpened ? SvgGroupCollapse : SvgGroupExpand}
|
|
318
387
|
className={Styles.navItemGroupToggle}
|
|
319
388
|
onClick={onToggleClick}
|
|
320
|
-
aria-label=
|
|
389
|
+
aria-label={`${submenuOpened ? 'Collapse' : 'Expand'} ${title} submenu`}
|
|
390
|
+
aria-expanded={submenuOpened}
|
|
391
|
+
aria-controls={submenuId}
|
|
321
392
|
data-cy="nav-item-group-expand"
|
|
322
393
|
/>,
|
|
323
394
|
// hide submenu tooltip for now
|
|
@@ -328,6 +399,7 @@ export const InternalSideNavigationGroup: FC<
|
|
|
328
399
|
</div>
|
|
329
400
|
{submenuOpened && (
|
|
330
401
|
<div
|
|
402
|
+
id={submenuId}
|
|
331
403
|
className={classNames(Styles.submenuWrapper, {
|
|
332
404
|
[Styles.submenuWrapperCollapsed]: !submenuOpened,
|
|
333
405
|
})}
|