@servicetitan/navigation 0.1.0 → 0.2.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 (48) hide show
  1. package/dist/components/header-navigation/header-navigation.d.ts +25 -1
  2. package/dist/components/header-navigation/header-navigation.d.ts.map +1 -1
  3. package/dist/components/header-navigation/header-navigation.js +19 -14
  4. package/dist/components/header-navigation/header-navigation.js.map +1 -1
  5. package/dist/components/header-navigation/header-navigation.module.less +32 -1
  6. package/dist/components/header-navigation/header-navigation.stories.d.ts +1 -0
  7. package/dist/components/header-navigation/header-navigation.stories.d.ts.map +1 -1
  8. package/dist/components/header-navigation/header-navigation.stories.js +34 -5
  9. package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
  10. package/dist/components/logo/logo.stories.js +1 -1
  11. package/dist/components/logo/logo.stories.js.map +1 -1
  12. package/dist/components/profile-dropdown/profile-dropdown.d.ts +53 -0
  13. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -0
  14. package/dist/components/profile-dropdown/profile-dropdown.js +60 -0
  15. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -0
  16. package/dist/components/profile-dropdown/profile-dropdown.module.less +136 -0
  17. package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts +16 -0
  18. package/dist/components/profile-dropdown/profile-dropdown.stories.d.ts.map +1 -0
  19. package/dist/components/profile-dropdown/profile-dropdown.stories.js +47 -0
  20. package/dist/components/profile-dropdown/profile-dropdown.stories.js.map +1 -0
  21. package/dist/components/profile-dropdown/profile-icon.d.ts +5 -0
  22. package/dist/components/profile-dropdown/profile-icon.d.ts.map +1 -0
  23. package/dist/components/profile-dropdown/profile-icon.js +3 -0
  24. package/dist/components/profile-dropdown/profile-icon.js.map +1 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/utils/navigation-context.d.ts +5 -0
  30. package/dist/utils/navigation-context.d.ts.map +1 -0
  31. package/dist/utils/navigation-context.js +6 -0
  32. package/dist/utils/navigation-context.js.map +1 -0
  33. package/dist/utils/navigation.d.ts +3 -2
  34. package/dist/utils/navigation.d.ts.map +1 -1
  35. package/package.json +2 -2
  36. package/src/components/header-navigation/header-navigation.module.less +32 -1
  37. package/src/components/header-navigation/header-navigation.module.less.d.ts +2 -0
  38. package/src/components/header-navigation/header-navigation.stories.tsx +105 -5
  39. package/src/components/header-navigation/header-navigation.tsx +141 -71
  40. package/src/components/logo/logo.stories.tsx +1 -1
  41. package/src/components/profile-dropdown/profile-dropdown.module.less +136 -0
  42. package/src/components/profile-dropdown/profile-dropdown.module.less.d.ts +18 -0
  43. package/src/components/profile-dropdown/profile-dropdown.stories.tsx +127 -0
  44. package/src/components/profile-dropdown/profile-dropdown.tsx +258 -0
  45. package/src/components/profile-dropdown/profile-icon.tsx +52 -0
  46. package/src/index.ts +4 -0
  47. package/src/utils/navigation-context.tsx +12 -0
  48. package/src/utils/navigation.ts +3 -2
@@ -0,0 +1,136 @@
1
+ /* stylelint-disable no-descending-specificity */
2
+ @import (reference) '@servicetitan/tokens/core/tokens.less';
3
+
4
+ .trigger-container {
5
+ height: 40px;
6
+ position: relative;
7
+
8
+ .profile-image {
9
+ height: 32px;
10
+ width: 32px;
11
+ border-radius: @border-radius-circular;
12
+ }
13
+
14
+ .info {
15
+ margin-left: @spacing-1;
16
+ max-width: 80px;
17
+ }
18
+
19
+ .avatar-badge {
20
+ position: absolute;
21
+ top: 8px;
22
+ left: 0;
23
+ height: 12px;
24
+ width: 12px;
25
+ border-radius: @border-radius-circular;
26
+ }
27
+
28
+ .badge {
29
+ position: absolute;
30
+ right: 16px;
31
+ color: @color-white;
32
+ font-size: @typescale-1;
33
+ display: flex;
34
+ justify-content: center;
35
+ align-items: center;
36
+ font-weight: @font-weight-semibold;
37
+ }
38
+
39
+ .badge-no-content {
40
+ top: 8px;
41
+ height: 12px;
42
+ width: 12px;
43
+ border-radius: @border-radius-2;
44
+ }
45
+
46
+ .badge-with-content {
47
+ top: 4px;
48
+ height: 16px;
49
+ min-width: 12px;
50
+ padding-left: 2px;
51
+ padding-right: 2px;
52
+ border-radius: 8px;
53
+ }
54
+
55
+ &.trigger-container-hint-arrow:first-child:before {
56
+ display: none;
57
+ content: '';
58
+ position: absolute;
59
+ background-color: @color-white;
60
+ height: 12px;
61
+ width: 12px;
62
+ bottom: -11px;
63
+ left: 14px;
64
+ z-index: (@z-index-popover + 2);
65
+ transform: rotateY(0deg) rotate(45deg);
66
+ border-left: 1px solid var(--colorsBorderGrey, @color-neutral-60);
67
+ border-top: 1px solid var(--colorsBorderGrey, @color-neutral-60);
68
+ }
69
+ }
70
+
71
+ .dropdown {
72
+ :global(.Popover__content) {
73
+ padding: @spacing-0;
74
+ }
75
+
76
+ :global(.Popover__divider) {
77
+ margin: @spacing-half @spacing-0;
78
+ width: 100%;
79
+ }
80
+
81
+ :global(.Popover__content).dropdown-content {
82
+ padding: @spacing-1 @spacing-0;
83
+ font-size: @typescale-2;
84
+ position: relative;
85
+ }
86
+
87
+ .dropdown-content-bottom-left {
88
+ .dropdown-content-wrapper::before {
89
+ content: '';
90
+ position: absolute;
91
+ top: -8px;
92
+ right: 8px;
93
+ height: 8px;
94
+ width: 8px;
95
+ background-color: coral;
96
+ }
97
+ }
98
+
99
+ .dropdown-section {
100
+ padding: @spacing-1 @spacing-2;
101
+ }
102
+
103
+ .dropdown-link {
104
+ display: block;
105
+ cursor: pointer;
106
+ color: @color-black;
107
+
108
+ &:hover {
109
+ background-color: rgba(0, 0, 0, 0.1);
110
+ }
111
+ }
112
+ }
113
+
114
+ .hint {
115
+ background-color: @color-white;
116
+ padding: @spacing-0 !important;
117
+
118
+ .hint-content {
119
+ padding: @spacing-1 @spacing-2;
120
+ background-color: inherit;
121
+
122
+ &::before {
123
+ content: '';
124
+ position: absolute;
125
+ top: -6px;
126
+ right: 29px;
127
+ height: 12px;
128
+ width: 12px;
129
+ background-color: inherit;
130
+ transform: rotateY(0deg) rotate(45deg);
131
+ border-left: 1px solid @color-neutral-60;
132
+ border-top: 1px solid @color-neutral-60;
133
+ z-index: (@z-index-popover + 2);
134
+ }
135
+ }
136
+ }
@@ -0,0 +1,18 @@
1
+ export const __esModule: true;
2
+ export const triggerContainer: string;
3
+ export const profileImage: string;
4
+ export const info: string;
5
+ export const avatarBadge: string;
6
+ export const badge: string;
7
+ export const badgeNoContent: string;
8
+ export const badgeWithContent: string;
9
+ export const triggerContainerHintArrow: string;
10
+ export const dropdown: string;
11
+ export const dropdownContent: string;
12
+ export const dropdownContentBottomLeft: string;
13
+ export const dropdownContentWrapper: string;
14
+ export const dropdownSection: string;
15
+ export const dropdownLink: string;
16
+ export const hint: string;
17
+ export const hintContent: string;
18
+
@@ -0,0 +1,127 @@
1
+ import { FC } from 'react';
2
+ import { HeaderNavigationComponentProps } from '../../utils/navigation';
3
+ import { HeaderNavigation } from '../header-navigation/header-navigation';
4
+ import { ProfileDropdown } from './profile-dropdown';
5
+
6
+ export default {
7
+ title: 'Navigation/ProfileDropdown',
8
+ component: ProfileDropdown,
9
+ parameters: {},
10
+ };
11
+
12
+ const NavLinkMock: FC<HeaderNavigationComponentProps> = props => (
13
+ <a
14
+ href={props.to}
15
+ target={props.target}
16
+ onClick={e => {
17
+ e.preventDefault();
18
+ }}
19
+ className={props.className}
20
+ >
21
+ {props.children}
22
+ </a>
23
+ );
24
+
25
+ export const profileDropdownDefault = () => (
26
+ <HeaderNavigation navigationComponent={NavLinkMock}>
27
+ <ProfileDropdown>
28
+ <ProfileDropdown.Link to="https://google.com">first link</ProfileDropdown.Link>
29
+ <ProfileDropdown.Link onClick={() => alert('second click')}>
30
+ second link
31
+ </ProfileDropdown.Link>
32
+ <ProfileDropdown.Divider />
33
+ <ProfileDropdown.Section>some content</ProfileDropdown.Section>
34
+ <ProfileDropdown.Divider />
35
+ <ProfileDropdown.Link to="https://google.com">third link</ProfileDropdown.Link>
36
+ </ProfileDropdown>
37
+ </HeaderNavigation>
38
+ );
39
+
40
+ export const profileDropdownWithLogo = () => (
41
+ <HeaderNavigation>
42
+ <ProfileDropdown
43
+ trigger={{
44
+ imageSrc: 'https://upload.wikimedia.org/wikipedia/en/1/11/Milhouse_Van_Houten.png',
45
+ }}
46
+ />
47
+ </HeaderNavigation>
48
+ );
49
+
50
+ export const profileDropdownWithErrorLogo = () => (
51
+ <HeaderNavigation>
52
+ <ProfileDropdown
53
+ trigger={{
54
+ imageSrc: 'https://some.incorrect.url/logo.png',
55
+ }}
56
+ />
57
+ </HeaderNavigation>
58
+ );
59
+
60
+ export const profileDropdownWithInfo = () => (
61
+ <HeaderNavigation>
62
+ <ProfileDropdown
63
+ trigger={{
64
+ info: { text: 'first', title: 'tenant user' },
65
+ avatarBadge: true,
66
+ }}
67
+ />
68
+ </HeaderNavigation>
69
+ );
70
+
71
+ export const profileDropdownWithCounter = () => (
72
+ <HeaderNavigation>
73
+ <ProfileDropdown
74
+ trigger={{
75
+ info: { text: 'first', title: 'tenant user' },
76
+ avatarBadge: true,
77
+ badge: { content: 3, className: 'bg-red-500' },
78
+ }}
79
+ />
80
+ </HeaderNavigation>
81
+ );
82
+
83
+ export const profileDropdownWithBothBadges = () => (
84
+ <HeaderNavigation>
85
+ <ProfileDropdown
86
+ trigger={{
87
+ avatarBadge: 'yellow-500',
88
+ badge: { className: 'bg-red-400' },
89
+ }}
90
+ />
91
+ </HeaderNavigation>
92
+ );
93
+
94
+ export const profileDropdownWithHintPopup = () => (
95
+ <HeaderNavigation navigationComponent={NavLinkMock}>
96
+ <ProfileDropdown
97
+ trigger={{
98
+ avatarBadge: 'yellow-500',
99
+ badge: { className: 'bg-red-400' },
100
+ }}
101
+ hintPopup={{
102
+ className: 'bg-blue-500-i c-white',
103
+ content: <div>hello</div>,
104
+ width: 's',
105
+ }}
106
+ >
107
+ <ProfileDropdown.Link to="https://google.com">first item</ProfileDropdown.Link>
108
+ <ProfileDropdown.Divider />
109
+ <ProfileDropdown.Section>second item</ProfileDropdown.Section>
110
+ </ProfileDropdown>
111
+ </HeaderNavigation>
112
+ );
113
+
114
+ export const profileDropdownWithHintAndInfoPopup = () => (
115
+ <HeaderNavigation navigationComponent={NavLinkMock}>
116
+ <ProfileDropdown
117
+ trigger={{
118
+ avatarBadge: 'yellow-500',
119
+ badge: { className: 'bg-red-400' },
120
+ info: { title: 'some text', text: 'qq' },
121
+ }}
122
+ hintPopup={{
123
+ content: <div>hello</div>,
124
+ }}
125
+ />
126
+ </HeaderNavigation>
127
+ );
@@ -0,0 +1,258 @@
1
+ import { BodyText, Icon, Popover, PopoverPropsStrict } from '@servicetitan/design-system';
2
+ import classNames from 'classnames';
3
+ import {
4
+ FC,
5
+ HTMLAttributeAnchorTarget,
6
+ MouseEvent,
7
+ MouseEventHandler,
8
+ ReactNode,
9
+ useCallback,
10
+ useContext,
11
+ useEffect,
12
+ useState,
13
+ } from 'react';
14
+
15
+ import { NavigationContext } from '../../utils/navigation-context';
16
+ import * as Styles from './profile-dropdown.module.less';
17
+ import { ProfileLogo } from './profile-icon';
18
+
19
+ interface ProfileDropdownTriggerProps {
20
+ className?: string;
21
+ info?: { title: string; text: string };
22
+ imageSrc?: string | null;
23
+ avatarBadge?: boolean | string;
24
+ badge?: { content?: number | string; className: string };
25
+ hintArrow?: boolean;
26
+ onClick?(e: MouseEvent): void;
27
+ }
28
+
29
+ const ProfileDropdownTrigger: FC<ProfileDropdownTriggerProps> = ({
30
+ avatarBadge,
31
+ badge,
32
+ className,
33
+ hintArrow,
34
+ imageSrc,
35
+ info,
36
+ onClick,
37
+ }) => {
38
+ const [avatarSource, setAvatarSource] = useState(imageSrc ?? '');
39
+ const [avatarSourceError, setAvatarSourceError] = useState(false);
40
+
41
+ useEffect(() => {
42
+ const src = imageSrc ?? '';
43
+
44
+ if (src === avatarSource) {
45
+ return;
46
+ }
47
+
48
+ setAvatarSource(src);
49
+ setAvatarSourceError(false);
50
+ }, [imageSrc, avatarSource]);
51
+
52
+ const onAvatarError = useCallback(() => {
53
+ setAvatarSourceError(true);
54
+ }, []);
55
+
56
+ return (
57
+ <div
58
+ className={classNames(
59
+ 'd-f align-items-center cursor-pointer position-relative p-y-1 p-x-1',
60
+ Styles.triggerContainer,
61
+ { [Styles.triggerContainerHintArrow]: hintArrow },
62
+ className
63
+ )}
64
+ onClick={onClick}
65
+ >
66
+ {avatarSource && !avatarSourceError ? (
67
+ <img
68
+ src={avatarSource}
69
+ className={Styles.profileImage}
70
+ onError={onAvatarError}
71
+ alt="user dropdown menu"
72
+ />
73
+ ) : (
74
+ <ProfileLogo size={24} />
75
+ )}
76
+
77
+ {!!info && (
78
+ <div className={Styles.info}>
79
+ <BodyText bold title={info.title} className="t-truncate c-white" size="xsmall">
80
+ {info.title}
81
+ </BodyText>
82
+ <BodyText
83
+ title={info.text}
84
+ className="t-truncate c-neutral-70 tt-uppercase"
85
+ size="xsmall"
86
+ >
87
+ {info.text}
88
+ </BodyText>
89
+ </div>
90
+ )}
91
+
92
+ <Icon className="m-l-half" name="expand_more" size={12} />
93
+
94
+ {!!avatarBadge && (
95
+ <div
96
+ className={classNames(
97
+ Styles.avatarBadge,
98
+ avatarBadge === true ? 'bg-blue-500' : `bg-${avatarBadge}`
99
+ )}
100
+ />
101
+ )}
102
+ {!!badge && (
103
+ <span
104
+ className={classNames(
105
+ Styles.badge,
106
+ badge.content ? Styles.badgeWithContent : Styles.badgeNoContent,
107
+ badge.className
108
+ )}
109
+ >
110
+ {badge.content}
111
+ </span>
112
+ )}
113
+ </div>
114
+ );
115
+ };
116
+
117
+ interface ProfileDropdownSectionProps {
118
+ children: ReactNode;
119
+ className?: string;
120
+ onClick?(e: MouseEvent): void;
121
+ }
122
+
123
+ const ProfileDropdownSection: FC<ProfileDropdownSectionProps> = ({
124
+ children,
125
+ className,
126
+ onClick,
127
+ }) => {
128
+ const clickHandler: MouseEventHandler<never> = e => {
129
+ if (onClick) {
130
+ onClick(e);
131
+ } else {
132
+ e.stopPropagation();
133
+ }
134
+ };
135
+
136
+ return (
137
+ <div className={classNames(Styles.dropdownSection, className)} onClick={clickHandler}>
138
+ {children}
139
+ </div>
140
+ );
141
+ };
142
+
143
+ type ProfileDropdownLinkProps = {
144
+ children: ReactNode;
145
+ } & (
146
+ | { target?: HTMLAttributeAnchorTarget; to: string; onClick?: () => void }
147
+ | { target?: never; to?: never; onClick(): void }
148
+ );
149
+
150
+ const ProfileDropdownLink: FC<ProfileDropdownLinkProps> = ({
151
+ children,
152
+ target,
153
+ to,
154
+ onClick,
155
+ }: ProfileDropdownLinkProps) => {
156
+ const NavigationComponent = useContext(NavigationContext);
157
+
158
+ const clickHandler = (e: MouseEvent<any>) => {
159
+ e.preventDefault();
160
+ onClick?.();
161
+ };
162
+
163
+ return to ? (
164
+ <NavigationComponent
165
+ className={classNames(Styles.dropdownSection, Styles.dropdownLink)}
166
+ target={target}
167
+ to={to}
168
+ >
169
+ {children}
170
+ </NavigationComponent>
171
+ ) : (
172
+ <a
173
+ className={classNames(Styles.dropdownSection, Styles.dropdownLink)}
174
+ onClick={clickHandler}
175
+ >
176
+ {children}
177
+ </a>
178
+ );
179
+ };
180
+
181
+ export interface ProfileDropdownProps {
182
+ children?: ReactNode;
183
+ trigger?: Omit<ProfileDropdownTriggerProps, 'onClick'>;
184
+ hintPopup?: {
185
+ className?: string;
186
+ content: ReactNode;
187
+ width?: PopoverPropsStrict['width'];
188
+ onClose?: () => void;
189
+ };
190
+ }
191
+
192
+ export interface ProfileDropdownType extends FC<ProfileDropdownProps> {
193
+ Divider: typeof Popover.Divider;
194
+ Link: typeof ProfileDropdownLink;
195
+ Section: typeof ProfileDropdownSection;
196
+ }
197
+
198
+ export const ProfileDropdown: ProfileDropdownType = (({ children, hintPopup, trigger }) => {
199
+ const [open, setOpen] = useState(false);
200
+ const onClose = useCallback(() => {
201
+ setOpen(false);
202
+ }, []);
203
+ const onTriggerClick = useCallback(
204
+ (e: MouseEvent) => {
205
+ e.stopPropagation();
206
+ setOpen(!open);
207
+ },
208
+ [open]
209
+ );
210
+ const hintShown = !!hintPopup && !open;
211
+
212
+ const triggerElement = (
213
+ <ProfileDropdownTrigger
214
+ {...trigger}
215
+ onClick={children ? onTriggerClick : undefined}
216
+ hintArrow={hintShown}
217
+ />
218
+ );
219
+
220
+ return (
221
+ <div className="position-relative">
222
+ {!!hintPopup && hintShown ? (
223
+ <Popover
224
+ direction="bl"
225
+ width={hintPopup.width ?? 'xs'}
226
+ trigger={triggerElement}
227
+ popoverContentClassName={Styles.hint}
228
+ open
229
+ >
230
+ <div className={classNames(Styles.hintContent, hintPopup.className)}>
231
+ {hintPopup.content}
232
+ </div>
233
+ </Popover>
234
+ ) : (
235
+ <Popover
236
+ direction="bl"
237
+ width="xs"
238
+ trigger={triggerElement}
239
+ open={open}
240
+ onClickOutside={onClose}
241
+ className={Styles.dropdown}
242
+ popoverContentClassName={classNames(
243
+ Styles.dropdownContent,
244
+ Styles.dropdownContentBottomLeft
245
+ )}
246
+ >
247
+ <div className={Styles.dropdownContentWrapper} onClick={onClose}>
248
+ {children}
249
+ </div>
250
+ </Popover>
251
+ )}
252
+ </div>
253
+ );
254
+ }) as ProfileDropdownType;
255
+
256
+ ProfileDropdown.Divider = Popover.Divider;
257
+ ProfileDropdown.Link = ProfileDropdownLink;
258
+ ProfileDropdown.Section = ProfileDropdownSection;
@@ -0,0 +1,52 @@
1
+ import { FC } from 'react';
2
+
3
+ export const ProfileLogo: FC<{ size: number }> = ({ size }) => (
4
+ <svg
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ version="1.1"
7
+ width={size}
8
+ height={size}
9
+ viewBox="0 0 256 256"
10
+ >
11
+ <g
12
+ stroke="none"
13
+ strokeWidth="0"
14
+ strokeDasharray="none"
15
+ strokeLinecap="butt"
16
+ strokeLinejoin="miter"
17
+ strokeMiterlimit="10"
18
+ fill="none"
19
+ fillRule="nonzero"
20
+ opacity="1"
21
+ transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)"
22
+ >
23
+ <path
24
+ d="M 45 53.718 c -10.022 0 -18.175 -8.153 -18.175 -18.175 S 34.978 17.368 45 17.368 c 10.021 0 18.175 8.153 18.175 18.175 S 55.021 53.718 45 53.718 z"
25
+ stroke="none"
26
+ strokeWidth="1"
27
+ strokeDasharray="none"
28
+ strokeLinecap="round"
29
+ strokeLinejoin="miter"
30
+ strokeMiterlimit="10"
31
+ fill="rgb(255,255,255)"
32
+ fillRule="nonzero"
33
+ opacity="1"
34
+ transform=" matrix(1 0 0 1 0 0) "
35
+ />
36
+
37
+ <path
38
+ d="M 45 0 C 20.187 0 0 20.187 0 45 c 0 24.813 20.187 45 45 45 c 24.813 0 45 -20.187 45 -45 C 90 20.187 69.813 0 45 0 z M 74.821 70.096 c -3.543 -5.253 -8.457 -9.568 -14.159 -12.333 c -2.261 -1.096 -4.901 -1.08 -7.247 0.047 c -2.638 1.268 -5.47 1.91 -8.415 1.91 c -2.945 0 -5.776 -0.643 -8.415 -1.91 c -2.343 -1.125 -4.984 -1.143 -7.247 -0.047 c -5.702 2.765 -10.616 7.08 -14.16 12.333 C 9.457 63.308 6 54.552 6 45 C 6 23.495 23.495 6 45 6 s 39 17.495 39 39 C 84 54.552 80.543 63.308 74.821 70.096 z"
39
+ stroke="none"
40
+ strokeWidth="1"
41
+ strokeDasharray="none"
42
+ strokeLinecap="round"
43
+ strokeLinejoin="miter"
44
+ strokeMiterlimit="10"
45
+ fill="rgb(255,255,255)"
46
+ fillRule="nonzero"
47
+ opacity="1"
48
+ transform=" matrix(1 0 0 1 0 0) "
49
+ />
50
+ </g>
51
+ </svg>
52
+ );
package/src/index.ts CHANGED
@@ -1 +1,5 @@
1
1
  export * from './components/header-navigation/header-navigation';
2
+ export * from './components/profile-dropdown/profile-dropdown';
3
+ export * from './components/logo/logo-company-title';
4
+ export * from './components/logo/logo-titan';
5
+ export * from './components/logo/logo-titan-text';
@@ -0,0 +1,12 @@
1
+ import { FC, createContext } from 'react';
2
+ import { NavLink } from 'react-router-dom';
3
+ import { HeaderNavigationComponentProps } from './navigation';
4
+
5
+ export const DefaultNavigationComponent: FC<HeaderNavigationComponentProps> = props => (
6
+ <NavLink
7
+ {...props}
8
+ isActive={props.isActive && ((_, { pathname }) => props.isActive!(pathname))}
9
+ />
10
+ );
11
+
12
+ export const NavigationContext = createContext(DefaultNavigationComponent);
@@ -1,5 +1,5 @@
1
1
  import { IconPropsStrict } from '@servicetitan/design-system';
2
- import { FC, ReactNode } from 'react';
2
+ import { FC, HTMLAttributeAnchorTarget, ReactNode } from 'react';
3
3
 
4
4
  export interface HeaderNavigationLinkData {
5
5
  /** link href */
@@ -38,11 +38,12 @@ export interface HeaderNavigationLinkData {
38
38
 
39
39
  export interface HeaderNavigationComponentPropsStrict {
40
40
  to: string;
41
- title: string;
41
+ title?: string;
42
42
  className?: string;
43
43
  activeClassName?: string;
44
44
  children: ReactNode;
45
45
  isActive?: (pathname: string) => boolean;
46
+ target?: HTMLAttributeAnchorTarget;
46
47
  }
47
48
 
48
49
  export interface HeaderNavigationComponentProps extends HeaderNavigationComponentPropsStrict {