@servicetitan/navigation 10.6.1 → 11.0.0-canary.237.0c461af.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/components/header-navigation/header-navigation-extra.stories.d.ts.map +1 -1
  2. package/dist/components/header-navigation/header-navigation-extra.stories.js +5 -5
  3. package/dist/components/header-navigation/header-navigation-extra.stories.js.map +1 -1
  4. package/dist/components/header-navigation/header-navigation-links.d.ts.map +1 -1
  5. package/dist/components/header-navigation/header-navigation-links.js +2 -2
  6. package/dist/components/header-navigation/header-navigation-links.js.map +1 -1
  7. package/dist/components/header-navigation/header-navigation-stacked.stories.d.ts.map +1 -1
  8. package/dist/components/header-navigation/header-navigation-stacked.stories.js +1 -1
  9. package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +1 -1
  10. package/dist/components/header-navigation/header-navigation.stories.d.ts.map +1 -1
  11. package/dist/components/header-navigation/header-navigation.stories.js +2 -2
  12. package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
  13. package/dist/components/header-navigation/with-tooltip.d.ts +1 -1
  14. package/dist/components/header-navigation/with-tooltip.d.ts.map +1 -1
  15. package/dist/components/left-navigation/header-navigation-tiny.stories.d.ts.map +1 -1
  16. package/dist/components/left-navigation/header-navigation-tiny.stories.js +2 -2
  17. package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
  18. package/dist/components/left-navigation/interface.d.ts +1 -1
  19. package/dist/components/left-navigation/interface.d.ts.map +1 -1
  20. package/dist/components/left-navigation/side-navigation-links-internal.d.ts +3 -1
  21. package/dist/components/left-navigation/side-navigation-links-internal.d.ts.map +1 -1
  22. package/dist/components/left-navigation/side-navigation-links-internal.js +3 -3
  23. package/dist/components/left-navigation/side-navigation-links-internal.js.map +1 -1
  24. package/dist/components/left-navigation/side-navigation.d.ts.map +1 -1
  25. package/dist/components/left-navigation/side-navigation.js +8 -7
  26. package/dist/components/left-navigation/side-navigation.js.map +1 -1
  27. package/dist/components/left-navigation/side-navigation.module.less +21 -19
  28. package/dist/components/links.d.ts.map +1 -1
  29. package/dist/components/links.js +7 -7
  30. package/dist/components/links.js.map +1 -1
  31. package/dist/components/logo/logo-company-title.d.ts +1 -0
  32. package/dist/components/logo/logo-company-title.d.ts.map +1 -1
  33. package/dist/components/logo/logo-company-title.js +2 -2
  34. package/dist/components/logo/logo-company-title.js.map +1 -1
  35. package/dist/components/profile-dropdown/profile-dropdown.d.ts +15 -9
  36. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  37. package/dist/components/profile-dropdown/profile-dropdown.js +7 -8
  38. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  39. package/dist/components/profile-dropdown/profile-dropdown.module.less +4 -0
  40. package/dist/components/profile-dropdown/profile-dropdown.stories.js +2 -2
  41. package/dist/components/profile-dropdown/profile-dropdown.stories.js.map +1 -1
  42. package/dist/components/titan-layout/index.d.ts +6 -0
  43. package/dist/components/titan-layout/index.d.ts.map +1 -0
  44. package/dist/components/titan-layout/index.js +6 -0
  45. package/dist/components/titan-layout/index.js.map +1 -0
  46. package/dist/components/titan-layout/interface-internal.d.ts +6 -0
  47. package/dist/components/titan-layout/interface-internal.d.ts.map +1 -0
  48. package/dist/components/titan-layout/interface-internal.js +2 -0
  49. package/dist/components/titan-layout/interface-internal.js.map +1 -0
  50. package/dist/components/titan-layout/interface.d.ts +21 -0
  51. package/dist/components/titan-layout/interface.d.ts.map +1 -0
  52. package/dist/components/titan-layout/interface.js +2 -0
  53. package/dist/components/titan-layout/interface.js.map +1 -0
  54. package/dist/components/titan-layout/layout-context.d.ts +20 -0
  55. package/dist/components/titan-layout/layout-context.d.ts.map +1 -0
  56. package/dist/components/titan-layout/layout-context.js +12 -0
  57. package/dist/components/titan-layout/layout-context.js.map +1 -0
  58. package/dist/components/titan-layout/layout-header-links.d.ts +7 -0
  59. package/dist/components/titan-layout/layout-header-links.d.ts.map +1 -0
  60. package/dist/components/titan-layout/layout-header-links.js +32 -0
  61. package/dist/components/titan-layout/layout-header-links.js.map +1 -0
  62. package/dist/components/titan-layout/layout-header.d.ts +20 -0
  63. package/dist/components/titan-layout/layout-header.d.ts.map +1 -0
  64. package/dist/components/titan-layout/layout-header.js +11 -0
  65. package/dist/components/titan-layout/layout-header.js.map +1 -0
  66. package/dist/components/titan-layout/layout-header.module.less +174 -0
  67. package/dist/components/titan-layout/layout-logo.d.ts +12 -0
  68. package/dist/components/titan-layout/layout-logo.d.ts.map +1 -0
  69. package/dist/components/titan-layout/layout-logo.js +15 -0
  70. package/dist/components/titan-layout/layout-logo.js.map +1 -0
  71. package/dist/components/titan-layout/layout-logo.stories.d.ts +13 -0
  72. package/dist/components/titan-layout/layout-logo.stories.d.ts.map +1 -0
  73. package/dist/components/titan-layout/layout-logo.stories.js +17 -0
  74. package/dist/components/titan-layout/layout-logo.stories.js.map +1 -0
  75. package/dist/components/titan-layout/layout-profile.d.ts +9 -0
  76. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -0
  77. package/dist/components/titan-layout/layout-profile.js +54 -0
  78. package/dist/components/titan-layout/layout-profile.js.map +1 -0
  79. package/dist/components/titan-layout/layout-profile.stories.d.ts +13 -0
  80. package/dist/components/titan-layout/layout-profile.stories.d.ts.map +1 -0
  81. package/dist/components/titan-layout/layout-profile.stories.js +13 -0
  82. package/dist/components/titan-layout/layout-profile.stories.js.map +1 -0
  83. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +46 -0
  84. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -0
  85. package/dist/components/titan-layout/layout-sidebar-links-internal.js +61 -0
  86. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -0
  87. package/dist/components/titan-layout/layout-sidebar-links.d.ts +6 -0
  88. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -0
  89. package/dist/components/titan-layout/layout-sidebar-links.js +21 -0
  90. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -0
  91. package/dist/components/titan-layout/layout-sidebar.d.ts +17 -0
  92. package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -0
  93. package/dist/components/titan-layout/layout-sidebar.js +65 -0
  94. package/dist/components/titan-layout/layout-sidebar.js.map +1 -0
  95. package/dist/components/titan-layout/layout-sidebar.module.less +516 -0
  96. package/dist/components/titan-layout/titan-layout.d.ts +38 -0
  97. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -0
  98. package/dist/components/titan-layout/titan-layout.js +147 -0
  99. package/dist/components/titan-layout/titan-layout.js.map +1 -0
  100. package/dist/components/titan-layout/titan-layout.module.less +103 -0
  101. package/dist/components/titan-layout/titan-layout.stories.d.ts +20 -0
  102. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -0
  103. package/dist/components/titan-layout/titan-layout.stories.js +80 -0
  104. package/dist/components/titan-layout/titan-layout.stories.js.map +1 -0
  105. package/dist/components/titan-layout/with-tooltip.d.ts +4 -0
  106. package/dist/components/titan-layout/with-tooltip.d.ts.map +1 -0
  107. package/dist/components/titan-layout/with-tooltip.js +4 -0
  108. package/dist/components/titan-layout/with-tooltip.js.map +1 -0
  109. package/dist/index.d.ts +2 -1
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +2 -1
  112. package/dist/index.js.map +1 -1
  113. package/dist/test/data.d.ts.map +1 -1
  114. package/dist/test/data.js +3 -3
  115. package/dist/test/data.js.map +1 -1
  116. package/dist/utils/navigation-legacy.d.ts +3 -1
  117. package/dist/utils/navigation-legacy.d.ts.map +1 -1
  118. package/dist/utils/use-breakpoint.d.ts +7 -0
  119. package/dist/utils/use-breakpoint.d.ts.map +1 -0
  120. package/dist/utils/use-breakpoint.js +13 -0
  121. package/dist/utils/use-breakpoint.js.map +1 -0
  122. package/package.json +5 -6
  123. package/src/components/header-navigation/header-navigation-extra.stories.tsx +7 -0
  124. package/src/components/header-navigation/header-navigation-links.tsx +2 -0
  125. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +5 -1
  126. package/src/components/header-navigation/header-navigation.stories.tsx +6 -1
  127. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +8 -2
  128. package/src/components/left-navigation/interface.ts +2 -2
  129. package/src/components/left-navigation/side-navigation-links-internal.tsx +21 -6
  130. package/src/components/left-navigation/side-navigation-links.tsx +1 -1
  131. package/src/components/left-navigation/side-navigation.module.less +21 -19
  132. package/src/components/left-navigation/side-navigation.module.less.d.ts +2 -1
  133. package/src/components/left-navigation/side-navigation.tsx +15 -8
  134. package/src/components/links.tsx +33 -13
  135. package/src/components/logo/logo-company-title.tsx +8 -6
  136. package/src/components/profile-dropdown/profile-dropdown.module.less +4 -0
  137. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +4 -4
  138. package/src/components/profile-dropdown/profile-dropdown.tsx +55 -51
  139. package/src/components/titan-layout/index.ts +5 -0
  140. package/src/components/titan-layout/interface-internal.ts +6 -0
  141. package/src/components/titan-layout/interface.ts +26 -0
  142. package/src/components/titan-layout/layout-context.tsx +30 -0
  143. package/src/components/titan-layout/layout-header-links.tsx +144 -0
  144. package/src/components/titan-layout/layout-header.module.less +174 -0
  145. package/src/components/titan-layout/layout-header.module.less.d.ts +16 -0
  146. package/src/components/titan-layout/layout-header.tsx +90 -0
  147. package/src/components/titan-layout/layout-logo.stories.tsx +31 -0
  148. package/src/components/titan-layout/layout-logo.tsx +57 -0
  149. package/src/components/titan-layout/layout-profile.stories.tsx +46 -0
  150. package/src/components/titan-layout/layout-profile.tsx +132 -0
  151. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +275 -0
  152. package/src/components/titan-layout/layout-sidebar-links.tsx +59 -0
  153. package/src/components/titan-layout/layout-sidebar.module.less +516 -0
  154. package/src/components/titan-layout/layout-sidebar.module.less.d.ts +48 -0
  155. package/src/components/titan-layout/layout-sidebar.tsx +295 -0
  156. package/src/components/titan-layout/titan-layout.module.less +103 -0
  157. package/src/components/titan-layout/titan-layout.module.less.d.ts +15 -0
  158. package/src/components/titan-layout/titan-layout.stories.tsx +332 -0
  159. package/src/components/titan-layout/titan-layout.tsx +365 -0
  160. package/src/components/titan-layout/with-tooltip.tsx +16 -0
  161. package/src/index.ts +2 -1
  162. package/src/test/data.tsx +3 -2
  163. package/src/utils/navigation-legacy.ts +3 -1
  164. package/src/utils/use-breakpoint.ts +19 -0
@@ -0,0 +1,31 @@
1
+ import { Chip } from '@servicetitan/anvil2';
2
+ import { ReactElement } from 'react';
3
+ import { withAnvil, withDefaultRedirects, withMemoryRouter } from '../../test/data';
4
+ import { TitanLayoutLogo, TitanLayoutLogoProps } from './layout-logo';
5
+ import { TitanLayout } from './titan-layout';
6
+
7
+ const withTitanLayout = (element: ReactElement<TitanLayoutLogoProps>) => () => (
8
+ <TitanLayout navigationMainItems={[]}>
9
+ {element}
10
+ <TitanLayout.Content>logo</TitanLayout.Content>
11
+ </TitanLayout>
12
+ );
13
+
14
+ export default {
15
+ title: 'Navigation/TitanLayoutLogo',
16
+ component: TitanLayoutLogo,
17
+ decorators: [withDefaultRedirects, withMemoryRouter, withAnvil],
18
+ parameters: {},
19
+ };
20
+
21
+ export const LogoDefault = withTitanLayout(<TitanLayoutLogo />);
22
+
23
+ export const LogoCompanyTitle = withTitanLayout(<TitanLayoutLogo title />);
24
+
25
+ export const LogoCommercial = withTitanLayout(
26
+ <TitanLayoutLogo title="Commercial" mantleFill="#2270EE" />
27
+ );
28
+
29
+ export const LogoWithPostfix = withTitanLayout(
30
+ <TitanLayoutLogo title postfix={<Chip className="m-l-2-i" label="demo" />} />
31
+ );
@@ -0,0 +1,57 @@
1
+ import classNames from 'classnames';
2
+ import { FC, Fragment, ReactNode } from 'react';
3
+ import { LogoCompanyTitle } from '../logo/logo-company-title';
4
+ import { LogoTitan, LogoTitanTitle, WrapperProps } from '../logo/logo-titan-text';
5
+ import { useTitanLayoutContext } from './layout-context';
6
+
7
+ export interface TitanLayoutLogoProps {
8
+ /** container class name */
9
+ className?: string;
10
+
11
+ title?: string | boolean;
12
+
13
+ postfix?: ReactNode;
14
+
15
+ logoWrapper?: WrapperProps;
16
+
17
+ mantleFill?: string;
18
+ }
19
+
20
+ const EmptyWrapper: FC<any> = ({ children }) => children;
21
+
22
+ export const TitanLayoutLogo: FC<TitanLayoutLogoProps> = ({
23
+ className,
24
+ mantleFill,
25
+ postfix,
26
+ title,
27
+ logoWrapper = EmptyWrapper,
28
+ }) => {
29
+ const {
30
+ breakpoint: { isMobile },
31
+ } = useTitanLayoutContext();
32
+
33
+ const Wrapper = logoWrapper;
34
+ const logoSize = isMobile ? 44 : 56;
35
+ const logoCompanySize = 48;
36
+
37
+ return (
38
+ <div className={classNames('d-f align-items-center', className)}>
39
+ {typeof title === 'string' ? (
40
+ <Fragment>
41
+ <LogoTitan size={logoSize} mantleFill={mantleFill} logoWrapper={Wrapper} />
42
+ {!isMobile && (
43
+ <LogoTitanTitle className="c-inherit m-l-1">{title}</LogoTitanTitle>
44
+ )}
45
+ </Fragment>
46
+ ) : title === true && !isMobile ? (
47
+ <Wrapper className="">
48
+ <LogoCompanyTitle height={logoCompanySize} />
49
+ </Wrapper>
50
+ ) : (
51
+ <LogoTitan size={logoSize} mantleFill={mantleFill} logoWrapper={Wrapper} />
52
+ )}
53
+
54
+ {!isMobile && postfix}
55
+ </div>
56
+ );
57
+ };
@@ -0,0 +1,46 @@
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
+ <TitanLayout.Content>profile</TitanLayout.Content>
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
+ );
@@ -0,0 +1,132 @@
1
+ import SvgAccountActive from '@servicetitan/anvil2/assets/icons/st/gnav_account_active.svg';
2
+ import SvgAccountInactive from '@servicetitan/anvil2/assets/icons/st/gnav_account_inactive.svg';
3
+
4
+ import { FC, useState } from 'react';
5
+ import { NavLinkComponentProps, NavigationComponentContext } from '../../utils/navigation-context';
6
+ import {
7
+ ProfileDropdown as DesktopProfileDropdown,
8
+ ProfileDropdownLinkProps,
9
+ ProfileDropdownProps,
10
+ ProfileDropdownSectionProps,
11
+ } from '../profile-dropdown/profile-dropdown';
12
+ import { NavigationComponentProps } from './interface-internal';
13
+ import { useTitanLayoutContext } from './layout-context';
14
+ import {
15
+ InternalSideNavigationGroup,
16
+ InternalSideNavigationGroupDivider,
17
+ InternalSideNavigationGroupLink,
18
+ InternalSideNavigationGroupTrigger,
19
+ } from './layout-sidebar-links-internal';
20
+
21
+ export type {
22
+ ProfileDropdownProps,
23
+ ProfileDropdownSectionProps,
24
+ ProfileDropdownLinkProps,
25
+ } from '../profile-dropdown/profile-dropdown';
26
+
27
+ const ExternalNavComponent: FC<NavLinkComponentProps> = ({ children, isActive, ...props }) => (
28
+ <a {...props}>{children}</a>
29
+ );
30
+
31
+ const ProfileDropdownContent: FC<ProfileDropdownProps> = props => {
32
+ const { breakpoint, NavigationComponent } = useTitanLayoutContext();
33
+ return breakpoint.isMobile ? (
34
+ <MobileProfileDropdown {...props} navigationComponent={NavigationComponent} />
35
+ ) : (
36
+ <NavigationComponentContext.Provider value={NavigationComponent}>
37
+ <DesktopProfileDropdown {...props} />
38
+ </NavigationComponentContext.Provider>
39
+ );
40
+ };
41
+ ProfileDropdownContent.displayName = 'ProfileDropdown';
42
+
43
+ const MobileProfileDropdown: FC<ProfileDropdownProps & NavigationComponentProps> = ({
44
+ children,
45
+ ...props
46
+ }) => {
47
+ const [expanded, setExpanded] = useState(false);
48
+ const onExpandToggle = () => setExpanded(!expanded);
49
+ return (
50
+ <InternalSideNavigationGroup
51
+ id="__profile"
52
+ to={undefined}
53
+ title="Profile"
54
+ icon={SvgAccountInactive}
55
+ iconActive={SvgAccountActive}
56
+ isActive={expanded}
57
+ {...props}
58
+ submenuExpanded={expanded}
59
+ onExpandToggle={onExpandToggle}
60
+ onClick={onExpandToggle}
61
+ tag={undefined}
62
+ >
63
+ {children}
64
+ </InternalSideNavigationGroup>
65
+ );
66
+ };
67
+
68
+ const ProfileDropdownDivider: FC = () => {
69
+ const { breakpoint } = useTitanLayoutContext();
70
+ return breakpoint.isMobile ? (
71
+ <InternalSideNavigationGroupDivider />
72
+ ) : (
73
+ <DesktopProfileDropdown.Divider />
74
+ );
75
+ };
76
+
77
+ const getText = (props: any): string | undefined => {
78
+ if (typeof props.children === 'string') {
79
+ return props.children;
80
+ }
81
+
82
+ if (typeof props.text === 'string') {
83
+ return props.text;
84
+ }
85
+
86
+ return undefined;
87
+ };
88
+
89
+ const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = props => {
90
+ const { breakpoint } = useTitanLayoutContext();
91
+ return breakpoint.isMobile ? (
92
+ <MobileProfileDropdownSection {...props} />
93
+ ) : (
94
+ <DesktopProfileDropdown.Section {...props} />
95
+ );
96
+ };
97
+ const MobileProfileDropdownSection: FC<ProfileDropdownSectionProps> = props => {
98
+ const text = getText(props);
99
+ return text ? (
100
+ <InternalSideNavigationGroupTrigger id={props.id} title={text} onClick={props.onClick} />
101
+ ) : null;
102
+ };
103
+
104
+ const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = props => {
105
+ const { breakpoint, NavigationComponent } = useTitanLayoutContext();
106
+ return breakpoint.isMobile ? (
107
+ <MobileProfileDropdownLink {...props} navigationComponent={NavigationComponent} />
108
+ ) : (
109
+ <DesktopProfileDropdown.Link {...props} />
110
+ );
111
+ };
112
+ const MobileProfileDropdownLink: FC<ProfileDropdownLinkProps & NavigationComponentProps> = ({
113
+ to,
114
+ navigationComponent,
115
+ ...props
116
+ }) => {
117
+ const text = getText(props);
118
+ return text ? (
119
+ <InternalSideNavigationGroupLink
120
+ {...props}
121
+ to={to}
122
+ title={text}
123
+ navigationComponent={props.external ? ExternalNavComponent : navigationComponent}
124
+ />
125
+ ) : null;
126
+ };
127
+
128
+ export const ProfileDropdown = Object.assign(ProfileDropdownContent, {
129
+ Divider: ProfileDropdownDivider,
130
+ Link: ProfileDropdownLink,
131
+ Section: ProfileDropdownSection,
132
+ });
@@ -0,0 +1,275 @@
1
+ import { Icon } from '@servicetitan/anvil2';
2
+ import SvgGroupCollapse from '@servicetitan/anvil2/assets/icons/material/round/expand_less.svg';
3
+ import SvgGroupExpand from '@servicetitan/anvil2/assets/icons/material/round/expand_more.svg';
4
+
5
+ import classNames from 'classnames';
6
+ import { FC, Fragment, MouseEvent, ReactNode } from 'react';
7
+ import { NavigationItemData, NavigationSubmenuItemData } from '../../utils/navigation';
8
+ import { getCounterTag } from '../../utils/side-nav';
9
+ import { BadgeTag, BadgeTagProps } from '../badge-tag';
10
+ import { TitanLayoutSidebarTriggerProps } from './interface';
11
+ import { NavigationComponentProps } from './interface-internal';
12
+ import * as Styles from './layout-sidebar.module.less';
13
+
14
+ export interface InternalSideNavigationItemContentProps
15
+ extends Omit<NavigationItemData, 'iconName' | 'to' | 'counter' | 'tag'> {
16
+ submenuExpanded: boolean | undefined;
17
+ tag: BadgeTagProps | undefined;
18
+ onExpandToggle?: (e: MouseEvent<never>) => void;
19
+ }
20
+
21
+ export const InternalSideNavigationItemContent: FC<InternalSideNavigationItemContentProps> = ({
22
+ icon,
23
+ iconActive,
24
+ iconClassName,
25
+ iconComponent: IconComponent,
26
+ tag,
27
+ title,
28
+ submenuExpanded,
29
+ onExpandToggle,
30
+ }) => (
31
+ <Fragment>
32
+ <div className={Styles.navItemIconWrapper}>
33
+ {IconComponent ? (
34
+ <i className={classNames(Styles.navIcon, iconClassName)}>
35
+ <IconComponent />
36
+ </i>
37
+ ) : (
38
+ <Fragment>
39
+ {icon && (
40
+ <Icon
41
+ svg={icon}
42
+ className={classNames(
43
+ Styles.navIcon,
44
+ Styles.navIconInactive,
45
+ iconClassName
46
+ )}
47
+ />
48
+ )}
49
+ {iconActive && (
50
+ <Icon
51
+ svg={iconActive}
52
+ className={classNames(
53
+ Styles.navIcon,
54
+ Styles.navIconActive,
55
+ iconClassName
56
+ )}
57
+ />
58
+ )}
59
+ </Fragment>
60
+ )}
61
+
62
+ <div className={Styles.navItemTextExpanded}>{title}</div>
63
+ {!!tag && (
64
+ <BadgeTag
65
+ data={tag}
66
+ className={Styles.navItemCounter}
67
+ longClassName={Styles.navItemCounterLong}
68
+ />
69
+ )}
70
+ {typeof submenuExpanded === 'boolean' && (
71
+ <div className={Styles.navItemGroupToggleWrapper}>
72
+ <Icon
73
+ svg={submenuExpanded ? SvgGroupCollapse : SvgGroupExpand}
74
+ className={Styles.navItemGroupToggle}
75
+ onClick={onExpandToggle}
76
+ />
77
+ <div className={Styles.navItemGroupToggleClick} onClick={onExpandToggle} />
78
+ </div>
79
+ )}
80
+ </div>
81
+
82
+ <div
83
+ className={classNames(Styles.navItemTextCollapsed, {
84
+ [Styles.navItemTextSmall]: !!title && title.length >= 10,
85
+ })}
86
+ >
87
+ {title}
88
+ </div>
89
+ </Fragment>
90
+ );
91
+
92
+ export interface InternalSideNavigationLinkProps
93
+ extends Omit<NavigationItemData, 'iconName' | 'counter' | 'tag'>,
94
+ NavigationComponentProps {
95
+ submenuExpanded: boolean | undefined;
96
+ dataPrefix?: string;
97
+ tag: BadgeTagProps | undefined;
98
+ onExpandToggle?: (e: MouseEvent<never>) => void;
99
+ }
100
+
101
+ export const internalNavigationContentContainerProps = ({
102
+ className,
103
+ icon,
104
+ iconActive,
105
+ iconComponent,
106
+ id,
107
+ isActive,
108
+ prefix,
109
+ isLink,
110
+ }: Omit<TitanLayoutSidebarTriggerProps, 'isActive' | 'tag'> & {
111
+ prefix: string;
112
+ isActive?: any;
113
+ isLink: boolean;
114
+ }) => ({
115
+ 'data-cy': `${prefix}-${id}`,
116
+ 'data-pendo': `${prefix}-${id}`,
117
+ 'className': classNames(Styles.navItem, className, {
118
+ [Styles.navLink]: isLink,
119
+ [Styles.navItemActive]: isActive === true,
120
+ [Styles.navItemIconSwitch]: !!icon && !!iconActive && !iconComponent,
121
+ }),
122
+ });
123
+
124
+ /** Side Navigation menu item (for internal usage) */
125
+ export const InternalSideNavigationLink: FC<InternalSideNavigationLinkProps> = ({
126
+ to,
127
+ className,
128
+ dataPrefix,
129
+ isActive,
130
+ navigationComponent: NavigationComponent,
131
+ submenuExpanded,
132
+ onExpandToggle,
133
+ ...props
134
+ }) => {
135
+ return (
136
+ <NavigationComponent
137
+ {...internalNavigationContentContainerProps({
138
+ ...props,
139
+ prefix: dataPrefix ?? 'navigation-item',
140
+ className,
141
+ isActive,
142
+ isLink: true,
143
+ })}
144
+ to={to}
145
+ isActive={typeof isActive === 'function' ? isActive : undefined}
146
+ activeClassName={Styles.navItemActive}
147
+ >
148
+ <InternalSideNavigationItemContent
149
+ submenuExpanded={submenuExpanded}
150
+ onExpandToggle={onExpandToggle}
151
+ {...props}
152
+ />
153
+ </NavigationComponent>
154
+ );
155
+ };
156
+
157
+ /** Side Navigation menu trigger (for internal usage) */
158
+ export const InternalSideNavigationTrigger: FC<
159
+ Omit<InternalSideNavigationLinkProps, 'to' | 'navigationComponent'> & { onClick?: () => void }
160
+ > = ({ className, dataPrefix, isActive, submenuExpanded, onExpandToggle, onClick, ...props }) => {
161
+ return (
162
+ <div
163
+ {...internalNavigationContentContainerProps({
164
+ ...props,
165
+ prefix: dataPrefix ?? 'navigation-item',
166
+ className,
167
+ isActive,
168
+ isLink: !!onClick,
169
+ })}
170
+ onClick={onClick}
171
+ >
172
+ <InternalSideNavigationItemContent
173
+ submenuExpanded={submenuExpanded}
174
+ onExpandToggle={onExpandToggle}
175
+ {...props}
176
+ />
177
+ </div>
178
+ );
179
+ };
180
+
181
+ export const InternalSideNavigationGroupLink: FC<
182
+ NavigationSubmenuItemData & NavigationComponentProps
183
+ > = ({
184
+ id,
185
+ counter,
186
+ tag,
187
+ title,
188
+ to,
189
+ isActive,
190
+ navigationComponent: NavigationComponent,
191
+ ...rest
192
+ }) => {
193
+ return (
194
+ <NavigationComponent
195
+ key={id}
196
+ data-cy={`navigation-item-${id}`}
197
+ data-pendo={`navigation-item-${id}`}
198
+ {...rest}
199
+ to={to}
200
+ className={classNames(Styles.submenuItem, Styles.submenuLink, {
201
+ [Styles.submenuLinkActive]: isActive === true,
202
+ })}
203
+ isActive={typeof isActive === 'function' ? isActive : undefined}
204
+ activeClassName={Styles.submenuLinkActive}
205
+ >
206
+ <span>{title}</span>
207
+ <BadgeTag data={getCounterTag(counter, tag)} className={Styles.submenuLinkCounter} />
208
+ </NavigationComponent>
209
+ );
210
+ };
211
+
212
+ export const InternalSideNavigationGroupTrigger: FC<
213
+ Omit<NavigationSubmenuItemData, 'to'> & { onClick?: (e: MouseEvent<any>) => void }
214
+ > = ({ id, counter, onClick, tag, title, isActive }) => {
215
+ return (
216
+ <div
217
+ data-cy={`navigation-item-${id}`}
218
+ data-pendo={`navigation-item-${id}`}
219
+ key={id}
220
+ className={classNames(Styles.submenuItem, {
221
+ [Styles.submenuLink]: !!onClick,
222
+ [Styles.submenuLinkActive]: isActive === true,
223
+ })}
224
+ onClick={onClick}
225
+ >
226
+ <span>{title}</span>
227
+ <BadgeTag data={getCounterTag(counter, tag)} className={Styles.submenuLinkCounter} />
228
+ </div>
229
+ );
230
+ };
231
+
232
+ export const InternalSideNavigationGroupDivider = () => {
233
+ return <div className={Styles.divider} />;
234
+ };
235
+
236
+ export const InternalSideNavigationGroup: FC<
237
+ Omit<NavigationItemData, 'tag' | 'counter' | 'to'> &
238
+ NavigationComponentProps & {
239
+ children: ReactNode;
240
+ submenuExpanded: boolean;
241
+ onExpandToggle?: (e: MouseEvent<never>) => void;
242
+ tag: BadgeTagProps | undefined;
243
+ to: NavigationItemData['to'] | undefined;
244
+ onClick?: () => void;
245
+ }
246
+ > = ({ children, submenuExpanded, to, onExpandToggle, onClick, ...props }) => {
247
+ return (
248
+ <div className={classNames(Styles.navGroupWrapper)}>
249
+ <div className={Styles.navGroupItem}>
250
+ {to ? (
251
+ <InternalSideNavigationLink
252
+ {...props}
253
+ to={to}
254
+ submenuExpanded={submenuExpanded}
255
+ onExpandToggle={onExpandToggle}
256
+ />
257
+ ) : (
258
+ <InternalSideNavigationTrigger
259
+ {...props}
260
+ submenuExpanded={submenuExpanded}
261
+ onExpandToggle={onExpandToggle}
262
+ onClick={onClick}
263
+ />
264
+ )}
265
+ </div>
266
+ <div
267
+ className={classNames(Styles.submenuWrapper, {
268
+ [Styles.submenuWrapperCollapsed]: !submenuExpanded,
269
+ })}
270
+ >
271
+ <div className={Styles.submenu}>{children}</div>
272
+ </div>
273
+ </div>
274
+ );
275
+ };
@@ -0,0 +1,59 @@
1
+ import { FC, ReactElement } from 'react';
2
+ import { getCounterTag } from '../../utils/side-nav';
3
+ import { TitanLayoutSidebarLinkProps, TitanLayoutSidebarTriggerProps } from './interface';
4
+ import { useTitanLayoutContext } from './layout-context';
5
+ import {
6
+ InternalSideNavigationLink,
7
+ InternalSideNavigationTrigger,
8
+ } from './layout-sidebar-links-internal';
9
+
10
+ const WrappedLink: FC<{
11
+ children: ReactElement<any>;
12
+ wrapper: NonNullable<TitanLayoutSidebarLinkProps['wrapper']>;
13
+ }> = ({ children, wrapper: WrapperComponent }) => {
14
+ const { sidebar } = useTitanLayoutContext();
15
+ return <WrapperComponent context={sidebar}>{children}</WrapperComponent>;
16
+ };
17
+
18
+ /** Side Navigation menu link */
19
+ export function TitanLayoutSidebarLink({ wrapper, ...props }: TitanLayoutSidebarLinkProps) {
20
+ const {
21
+ NavigationComponent,
22
+ breakpoint: { isMobile },
23
+ } = useTitanLayoutContext();
24
+
25
+ const element = (
26
+ <InternalSideNavigationLink
27
+ {...props}
28
+ navigationComponent={NavigationComponent}
29
+ submenuExpanded={undefined}
30
+ dataPrefix="navigation-link"
31
+ tag={getCounterTag(props.counter, props.tag)}
32
+ />
33
+ );
34
+
35
+ return wrapper && !isMobile ? <WrappedLink wrapper={wrapper}>{element}</WrappedLink> : element;
36
+ }
37
+
38
+ /** Side Navigation menu trigger */
39
+ export function TitanLayoutSidebarTrigger({
40
+ wrapper,
41
+ onMobileClick,
42
+ onClick,
43
+ ...props
44
+ }: TitanLayoutSidebarTriggerProps) {
45
+ const {
46
+ breakpoint: { isMobile },
47
+ } = useTitanLayoutContext();
48
+
49
+ const element = (
50
+ <InternalSideNavigationTrigger
51
+ {...props}
52
+ submenuExpanded={undefined}
53
+ dataPrefix="navigation-trigger"
54
+ tag={getCounterTag(props.counter, props.tag)}
55
+ onClick={isMobile && !!onMobileClick ? onMobileClick : onClick}
56
+ />
57
+ );
58
+ return wrapper && !isMobile ? <WrappedLink wrapper={wrapper}>{element}</WrappedLink> : element;
59
+ }