@servicetitan/navigation 9.0.1 → 9.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.
- package/dist/components/counter-tag.d.ts +1 -4
- package/dist/components/counter-tag.d.ts.map +1 -1
- package/dist/components/counter-tag.js.map +1 -1
- package/dist/components/left-navigation/header-navigation-tiny-links.d.ts.map +1 -1
- package/dist/components/left-navigation/header-navigation-tiny-links.js +1 -1
- package/dist/components/left-navigation/header-navigation-tiny-links.js.map +1 -1
- package/dist/components/left-navigation/index.d.ts +2 -0
- package/dist/components/left-navigation/index.d.ts.map +1 -1
- package/dist/components/left-navigation/index.js +2 -0
- package/dist/components/left-navigation/index.js.map +1 -1
- package/dist/components/left-navigation/interface-internal.d.ts +10 -0
- package/dist/components/left-navigation/interface-internal.d.ts.map +1 -0
- package/dist/components/left-navigation/interface-internal.js +2 -0
- package/dist/components/left-navigation/interface-internal.js.map +1 -0
- package/dist/components/left-navigation/interface.d.ts +19 -0
- package/dist/components/left-navigation/interface.d.ts.map +1 -0
- package/dist/components/left-navigation/interface.js +2 -0
- package/dist/components/left-navigation/interface.js.map +1 -0
- package/dist/components/left-navigation/side-navigation-context.d.ts +8 -0
- package/dist/components/left-navigation/side-navigation-context.d.ts.map +1 -0
- package/dist/components/left-navigation/side-navigation-context.js +7 -0
- package/dist/components/left-navigation/side-navigation-context.js.map +1 -0
- package/dist/components/left-navigation/side-navigation-links-internal.d.ts +23 -0
- package/dist/components/left-navigation/side-navigation-links-internal.d.ts.map +1 -0
- package/dist/components/left-navigation/side-navigation-links-internal.js +29 -0
- package/dist/components/left-navigation/side-navigation-links-internal.js.map +1 -0
- package/dist/components/left-navigation/side-navigation-links.d.ts +6 -0
- package/dist/components/left-navigation/side-navigation-links.d.ts.map +1 -0
- package/dist/components/left-navigation/side-navigation-links.js +26 -0
- package/dist/components/left-navigation/side-navigation-links.js.map +1 -0
- package/dist/components/left-navigation/side-navigation.d.ts +13 -13
- package/dist/components/left-navigation/side-navigation.d.ts.map +1 -1
- package/dist/components/left-navigation/side-navigation.js +45 -30
- package/dist/components/left-navigation/side-navigation.js.map +1 -1
- package/dist/components/left-navigation/side-navigation.module.less +11 -4
- package/dist/components/left-navigation/side-navigation.stories.d.ts +5 -1
- package/dist/components/left-navigation/side-navigation.stories.d.ts.map +1 -1
- package/dist/components/left-navigation/side-navigation.stories.js +21 -2
- package/dist/components/left-navigation/side-navigation.stories.js.map +1 -1
- package/dist/utils/counter-tag.d.ts +8 -0
- package/dist/utils/counter-tag.d.ts.map +1 -0
- package/dist/utils/counter-tag.js +2 -0
- package/dist/utils/counter-tag.js.map +1 -0
- package/dist/utils/side-nav.d.ts +3 -0
- package/dist/utils/side-nav.d.ts.map +1 -0
- package/dist/utils/side-nav.js +27 -0
- package/dist/utils/side-nav.js.map +1 -0
- package/package.json +2 -2
- package/src/components/counter-tag.tsx +1 -5
- package/src/components/left-navigation/header-navigation-tiny-links.tsx +3 -0
- package/src/components/left-navigation/index.ts +2 -0
- package/src/components/left-navigation/interface-internal.ts +11 -0
- package/src/components/left-navigation/interface.ts +23 -0
- package/src/components/left-navigation/side-navigation-context.tsx +13 -0
- package/src/components/left-navigation/side-navigation-links-internal.tsx +128 -0
- package/src/components/left-navigation/side-navigation-links.tsx +51 -0
- package/src/components/left-navigation/side-navigation.module.less +11 -4
- package/src/components/left-navigation/side-navigation.module.less.d.ts +2 -1
- package/src/components/left-navigation/side-navigation.stories.tsx +58 -4
- package/src/components/left-navigation/side-navigation.tsx +123 -163
- package/src/utils/counter-tag.ts +11 -0
- package/src/utils/side-nav.ts +34 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Popover } from '@servicetitan/anvil2';
|
|
2
3
|
import { Page } from '@servicetitan/design-system';
|
|
3
4
|
import { useState } from 'react';
|
|
4
5
|
import { LocationInfo, items, withAnvil, withDefaultRedirects, withMemoryRouter, } from '../../test/data';
|
|
5
|
-
import { SideNavigation } from './';
|
|
6
|
+
import { SideNavigation, SideNavigationLink, SideNavigationTrigger, } from './';
|
|
6
7
|
const layout = (Story) => {
|
|
7
8
|
return (_jsxs("div", { className: "d-f border", style: { height: '800px' }, children: [_jsx(Story, {}), _jsx("div", { className: "flex-grow-1 flex-basis-0", children: _jsx(Page, { children: _jsx(LocationInfo, {}) }) })] }));
|
|
8
9
|
};
|
|
@@ -27,7 +28,7 @@ export const DefaultSideNavigation = () => {
|
|
|
27
28
|
items.priceBook,
|
|
28
29
|
items.pointOfSale,
|
|
29
30
|
items.reports,
|
|
30
|
-
],
|
|
31
|
+
], children: _jsx(SideNavigation.Top, { children: _jsx(SideNavigationLink, { ...items.tasks }) }) }));
|
|
31
32
|
};
|
|
32
33
|
export const SideNavigationLinksOnly = () => {
|
|
33
34
|
const [expanded, setExpanded] = useState(undefined);
|
|
@@ -61,4 +62,22 @@ export const SideNavigationWithSubmenu = () => {
|
|
|
61
62
|
items.projects,
|
|
62
63
|
] }));
|
|
63
64
|
};
|
|
65
|
+
const SideLinkPopoverWrapper = ({ children, context }) => {
|
|
66
|
+
return (_jsxs(Popover, { placement: "right", openOnHover: true, children: [_jsx(Popover.Trigger, { children: props => _jsx("div", { ...props, children: children }) }), _jsx(Popover.Content, { style: context.styles.popoverContent, children: "popover content" })] }));
|
|
67
|
+
};
|
|
68
|
+
export const SideNavigationWithCustomTopElements = () => {
|
|
69
|
+
const [expanded, setExpanded] = useState(undefined);
|
|
70
|
+
return (_jsx(SideNavigation, { expanded: expanded, onExpandedChange: setExpanded, items: [
|
|
71
|
+
items.dashboard,
|
|
72
|
+
items.schedule,
|
|
73
|
+
items.dispatch,
|
|
74
|
+
items.accountingWithSubmenu,
|
|
75
|
+
items.purchasingWithSubmenu,
|
|
76
|
+
items.followUpsWithSubmenu,
|
|
77
|
+
items.reports,
|
|
78
|
+
items.marketing,
|
|
79
|
+
items.priceBook,
|
|
80
|
+
items.projects,
|
|
81
|
+
], children: _jsxs(SideNavigation.Top, { children: [_jsx(SideNavigationLink, { ...items.calls }), _jsx(SideNavigationLink, { ...items.tasks }), _jsx(SideNavigationTrigger, { ...items.marketing, isActive: false, wrapper: SideLinkPopoverWrapper })] }) }));
|
|
82
|
+
};
|
|
64
83
|
//# sourceMappingURL=side-navigation.stories.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"side-navigation.stories.js","sourceRoot":"","sources":["../../../src/components/left-navigation/side-navigation.stories.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AACnD,OAAO,
|
|
1
|
+
{"version":3,"file":"side-navigation.stories.js","sourceRoot":"","sources":["../../../src/components/left-navigation/side-navigation.stories.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CounterTagProps } from '../components/counter-tag';
|
|
2
|
+
export interface CounterTagPropsStrict {
|
|
3
|
+
value: number | boolean;
|
|
4
|
+
className?: string;
|
|
5
|
+
}
|
|
6
|
+
export type CounterTagType = boolean | number | CounterTagProps;
|
|
7
|
+
export declare const isCounterPropsObject: (tag?: CounterTagType) => tag is CounterTagProps;
|
|
8
|
+
//# sourceMappingURL=counter-tag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter-tag.d.ts","sourceRoot":"","sources":["../../src/utils/counter-tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,eAAe,CAAC;AAEhE,eAAO,MAAM,oBAAoB,SAAU,cAAc,KAAG,GAAG,IAAI,eACtB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter-tag.js","sourceRoot":"","sources":["../../src/utils/counter-tag.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAoB,EAA0B,EAAE,CACjF,CAAC,CAAC,GAAG,IAAK,GAAW,CAAC,KAAK,KAAK,SAAS,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { HeaderNavigationItemData, HeaderNavigationItemSubmenu } from './navigation';
|
|
2
|
+
export declare function getSubmenuGroupTag(submenu: HeaderNavigationItemSubmenu | undefined, defaultTag: HeaderNavigationItemData['tag']): HeaderNavigationItemData['tag'];
|
|
3
|
+
//# sourceMappingURL=side-nav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"side-nav.d.ts","sourceRoot":"","sources":["../../src/utils/side-nav.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAErF,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,2BAA2B,GAAG,SAAS,EAChD,UAAU,EAAE,wBAAwB,CAAC,KAAK,CAAC,GAC5C,wBAAwB,CAAC,KAAK,CAAC,CA2BjC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { isCounterPropsObject } from './counter-tag';
|
|
2
|
+
export function getSubmenuGroupTag(submenu, defaultTag) {
|
|
3
|
+
if (!submenu) {
|
|
4
|
+
return defaultTag;
|
|
5
|
+
}
|
|
6
|
+
let tagValue = undefined;
|
|
7
|
+
for (const group of submenu.groups) {
|
|
8
|
+
for (const link of group.links) {
|
|
9
|
+
const ltv = isCounterPropsObject(link.tag)
|
|
10
|
+
? link.tag.value
|
|
11
|
+
: link.tag;
|
|
12
|
+
if (ltv) {
|
|
13
|
+
if (typeof ltv === 'number') {
|
|
14
|
+
if (typeof tagValue !== 'number') {
|
|
15
|
+
tagValue = 0;
|
|
16
|
+
}
|
|
17
|
+
tagValue += ltv;
|
|
18
|
+
}
|
|
19
|
+
else if (typeof tagValue !== 'number') {
|
|
20
|
+
tagValue = true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return tagValue !== null && tagValue !== void 0 ? tagValue : defaultTag;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=side-nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"side-nav.js","sourceRoot":"","sources":["../../src/utils/side-nav.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGrD,MAAM,UAAU,kBAAkB,CAC9B,OAAgD,EAChD,UAA2C;IAE3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,UAAU,CAAC;IACtB,CAAC;IAED,IAAI,QAAQ,GAAiC,SAAS,CAAC;IAEvD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAiC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC;gBACpE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK;gBAChB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAEf,IAAI,GAAG,EAAE,CAAC;gBACN,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;oBAC1B,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;wBAC/B,QAAQ,GAAG,CAAC,CAAC;oBACjB,CAAC;oBACD,QAAQ,IAAI,GAAG,CAAC;gBACpB,CAAC;qBAAM,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;oBACtC,QAAQ,GAAG,IAAI,CAAC;gBACpB,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,aAAR,QAAQ,cAAR,QAAQ,GAAI,UAAU,CAAC;AAClC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/navigation",
|
|
3
|
-
"version": "9.0
|
|
3
|
+
"version": "9.2.0",
|
|
4
4
|
"description": "Navigation components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"less": true,
|
|
44
44
|
"webpack": false
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "97dd433c1d3ad452a2445174e297ffa4b23c0a05"
|
|
47
47
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { Tag } from '@servicetitan/design-system';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { FC } from 'react';
|
|
4
|
-
|
|
5
|
-
export interface CounterTagPropsStrict {
|
|
6
|
-
value: number | boolean;
|
|
7
|
-
className?: string;
|
|
8
|
-
}
|
|
4
|
+
import { CounterTagPropsStrict } from '../utils/counter-tag';
|
|
9
5
|
|
|
10
6
|
export interface CounterTagProps extends CounterTagPropsStrict {
|
|
11
7
|
[key: string]: any;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { NavLinkComponentProps } from '../../utils/navigation';
|
|
3
|
+
import { SideNavigationExpandedState } from './interface';
|
|
4
|
+
|
|
5
|
+
export interface NavigationComponentProps {
|
|
6
|
+
navigationComponent: FC<NavLinkComponentProps>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SideNavigationExpandedProps {
|
|
10
|
+
expanded?: SideNavigationExpandedState;
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FC, ReactElement } from 'react';
|
|
2
|
+
import { HeaderNavigationItemData } from '../../utils/navigation';
|
|
3
|
+
import { SideNavigationContextType } from './side-navigation-context';
|
|
4
|
+
|
|
5
|
+
export interface SideNavigationExpandedState {
|
|
6
|
+
bar: boolean;
|
|
7
|
+
submenus?: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface SideNavigationLinkWrapperProps {
|
|
11
|
+
children: ReactElement<SideNavigationLinkProps> | ReactElement<SideNavigationTriggerProps>;
|
|
12
|
+
context: SideNavigationContextType;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface SideNavigationLinkProps
|
|
16
|
+
extends Omit<HeaderNavigationItemData, 'iconName' | 'submenu'> {
|
|
17
|
+
wrapper?: FC<SideNavigationLinkWrapperProps>;
|
|
18
|
+
}
|
|
19
|
+
export interface SideNavigationTriggerProps
|
|
20
|
+
extends Omit<SideNavigationLinkProps, 'to' | 'isActive'> {
|
|
21
|
+
isActive?: boolean;
|
|
22
|
+
wrapper?: FC<SideNavigationLinkWrapperProps>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CSSProperties, createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface SideNavigationContextType {
|
|
4
|
+
styles: {
|
|
5
|
+
popoverContent: CSSProperties;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const SideNavigationContext = createContext<SideNavigationContextType>({
|
|
10
|
+
styles: {
|
|
11
|
+
popoverContent: {},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
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 } from 'react';
|
|
7
|
+
import { HeaderNavigationItemData } from '../../utils/navigation';
|
|
8
|
+
import { CounterTag } from '../counter-tag';
|
|
9
|
+
import { SideNavigationTriggerProps } from './interface';
|
|
10
|
+
import { NavigationComponentProps, SideNavigationExpandedProps } from './interface-internal';
|
|
11
|
+
import * as Styles from './side-navigation.module.less';
|
|
12
|
+
|
|
13
|
+
export interface InternalSideNavigationItemContentProps
|
|
14
|
+
extends Omit<HeaderNavigationItemData, 'iconName' | 'to' | ''> {
|
|
15
|
+
submenuExpanded: boolean | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const InternalSideNavigationItemContent: FC<InternalSideNavigationItemContentProps> = ({
|
|
19
|
+
icon,
|
|
20
|
+
iconActive,
|
|
21
|
+
iconClassName,
|
|
22
|
+
iconComponent: IconComponent,
|
|
23
|
+
tag,
|
|
24
|
+
title,
|
|
25
|
+
submenuExpanded,
|
|
26
|
+
}) => (
|
|
27
|
+
<Fragment>
|
|
28
|
+
<div className={Styles.navigationItemIconWrapper}>
|
|
29
|
+
{IconComponent ? (
|
|
30
|
+
<i className={classNames(Styles.navigationIcon, iconClassName)}>
|
|
31
|
+
<IconComponent />
|
|
32
|
+
</i>
|
|
33
|
+
) : (
|
|
34
|
+
<Fragment>
|
|
35
|
+
{icon && (
|
|
36
|
+
<Icon
|
|
37
|
+
svg={icon}
|
|
38
|
+
className={classNames(
|
|
39
|
+
Styles.navigationIcon,
|
|
40
|
+
Styles.navigationIconInactive,
|
|
41
|
+
iconClassName
|
|
42
|
+
)}
|
|
43
|
+
/>
|
|
44
|
+
)}
|
|
45
|
+
{iconActive && (
|
|
46
|
+
<Icon
|
|
47
|
+
svg={iconActive}
|
|
48
|
+
className={classNames(
|
|
49
|
+
Styles.navigationIcon,
|
|
50
|
+
Styles.navigationIconActive,
|
|
51
|
+
iconClassName
|
|
52
|
+
)}
|
|
53
|
+
/>
|
|
54
|
+
)}
|
|
55
|
+
</Fragment>
|
|
56
|
+
)}
|
|
57
|
+
|
|
58
|
+
<div className={Styles.navigationItemTextExpanded}>{title}</div>
|
|
59
|
+
{!!tag && <CounterTag data={tag} className={Styles.navigationItemCounter} />}
|
|
60
|
+
{typeof submenuExpanded === 'boolean' && (
|
|
61
|
+
<Icon
|
|
62
|
+
svg={submenuExpanded ? SvgGroupCollapse : SvgGroupExpand}
|
|
63
|
+
className={Styles.navigationItemGroupToggle}
|
|
64
|
+
/>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div
|
|
69
|
+
className={classNames(Styles.navigationItemTextCollapsed, {
|
|
70
|
+
[Styles.navigationItemTextSmall]: title.length >= 10,
|
|
71
|
+
})}
|
|
72
|
+
>
|
|
73
|
+
{title}
|
|
74
|
+
</div>
|
|
75
|
+
</Fragment>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export interface InternalSideNavigationLinkProps
|
|
79
|
+
extends Omit<HeaderNavigationItemData, 'iconName'>,
|
|
80
|
+
NavigationComponentProps,
|
|
81
|
+
SideNavigationExpandedProps {
|
|
82
|
+
submenuExpanded: boolean | undefined;
|
|
83
|
+
dataPrefix?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const internalNavigationContentContainerProps = ({
|
|
87
|
+
className,
|
|
88
|
+
icon,
|
|
89
|
+
iconActive,
|
|
90
|
+
iconComponent,
|
|
91
|
+
id,
|
|
92
|
+
isActive,
|
|
93
|
+
prefix,
|
|
94
|
+
}: Omit<SideNavigationTriggerProps, 'isActive'> & { prefix: string; isActive?: any }) => ({
|
|
95
|
+
'data-cy': `${prefix}-${id}`,
|
|
96
|
+
'data-pendo': `${prefix}-${id}`,
|
|
97
|
+
'className': classNames(Styles.navigationItem, className, {
|
|
98
|
+
[Styles.navigationItemActive]: isActive === true,
|
|
99
|
+
[Styles.navigationItemIconSwitch]: !!icon && !!iconActive && !iconComponent,
|
|
100
|
+
}),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/** Side Navigation menu item (for internal usage) */
|
|
104
|
+
export const InternalSideNavigationLink: FC<InternalSideNavigationLinkProps> = ({
|
|
105
|
+
to,
|
|
106
|
+
className,
|
|
107
|
+
dataPrefix,
|
|
108
|
+
isActive,
|
|
109
|
+
navigationComponent: NavigationComponent,
|
|
110
|
+
submenuExpanded,
|
|
111
|
+
...props
|
|
112
|
+
}) => {
|
|
113
|
+
return (
|
|
114
|
+
<NavigationComponent
|
|
115
|
+
{...internalNavigationContentContainerProps({
|
|
116
|
+
...props,
|
|
117
|
+
prefix: dataPrefix ?? 'navigation-item',
|
|
118
|
+
className,
|
|
119
|
+
isActive,
|
|
120
|
+
})}
|
|
121
|
+
to={to}
|
|
122
|
+
isActive={typeof isActive === 'function' ? isActive : undefined}
|
|
123
|
+
activeClassName={Styles.navigationItemActive}
|
|
124
|
+
>
|
|
125
|
+
<InternalSideNavigationItemContent submenuExpanded={submenuExpanded} {...props} />
|
|
126
|
+
</NavigationComponent>
|
|
127
|
+
);
|
|
128
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import { FC, ReactElement, useContext } from 'react';
|
|
3
|
+
import { NavigationComponentContext } from '../../utils/navigation-context';
|
|
4
|
+
import { SideNavigationLinkProps, SideNavigationTriggerProps } from './interface';
|
|
5
|
+
import { SideNavigationContext } from './side-navigation-context';
|
|
6
|
+
import {
|
|
7
|
+
InternalSideNavigationItemContent,
|
|
8
|
+
InternalSideNavigationLink,
|
|
9
|
+
internalNavigationContentContainerProps,
|
|
10
|
+
} from './side-navigation-links-internal';
|
|
11
|
+
|
|
12
|
+
const WrappedLink: FC<{
|
|
13
|
+
children: ReactElement;
|
|
14
|
+
wrapper: NonNullable<SideNavigationLinkProps['wrapper']>;
|
|
15
|
+
}> = ({ children, wrapper: WrapperComponent }) => {
|
|
16
|
+
return (
|
|
17
|
+
<WrapperComponent context={useContext(SideNavigationContext)}>{children}</WrapperComponent>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
/** Side Navigation menu link */
|
|
21
|
+
export function SideNavigationLink({ wrapper, ...props }: SideNavigationLinkProps) {
|
|
22
|
+
const NavigationComponent = useContext(NavigationComponentContext);
|
|
23
|
+
|
|
24
|
+
const element = (
|
|
25
|
+
<InternalSideNavigationLink
|
|
26
|
+
{...props}
|
|
27
|
+
navigationComponent={NavigationComponent}
|
|
28
|
+
submenuExpanded={undefined}
|
|
29
|
+
dataPrefix="navigation-link"
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
return wrapper ? <WrappedLink wrapper={wrapper}>{element}</WrappedLink> : element;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Side Navigation menu trigger */
|
|
37
|
+
export function SideNavigationTrigger({ wrapper, ...props }: SideNavigationTriggerProps) {
|
|
38
|
+
const element = (
|
|
39
|
+
<div
|
|
40
|
+
{...internalNavigationContentContainerProps({
|
|
41
|
+
...props,
|
|
42
|
+
prefix: 'navigation-trigger',
|
|
43
|
+
className: classNames(props.className, 'cursor-pointer'),
|
|
44
|
+
isActive: props.isActive,
|
|
45
|
+
})}
|
|
46
|
+
>
|
|
47
|
+
<InternalSideNavigationItemContent submenuExpanded={undefined} {...props} />
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
return wrapper ? <WrappedLink wrapper={wrapper}>{element}</WrappedLink> : element;
|
|
51
|
+
}
|
|
@@ -44,7 +44,10 @@
|
|
|
44
44
|
padding: @spacing-half;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
.navigation-item-text {
|
|
47
|
+
.navigation-item-text-expanded {
|
|
48
|
+
display: none;
|
|
49
|
+
}
|
|
50
|
+
.navigation-item-text-collapsed {
|
|
48
51
|
font-family: @base-font-family;
|
|
49
52
|
font-size: 11px;
|
|
50
53
|
line-height: 11px;
|
|
@@ -52,7 +55,7 @@
|
|
|
52
55
|
text-align: center;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
.navigation-item-text.navigation-item-text-small {
|
|
58
|
+
.navigation-item-text-collapsed.navigation-item-text-small {
|
|
56
59
|
font-size: 10.5px;
|
|
57
60
|
}
|
|
58
61
|
}
|
|
@@ -81,13 +84,17 @@
|
|
|
81
84
|
padding: @spacing-1 @spacing-half;
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
.navigation-item-text {
|
|
87
|
+
.navigation-item-text-expanded {
|
|
85
88
|
font-family: @base-font-family;
|
|
86
89
|
font-size: @typescale-3;
|
|
87
90
|
padding-left: @spacing-1;
|
|
88
91
|
flex: 1;
|
|
89
92
|
}
|
|
90
93
|
|
|
94
|
+
.navigation-item-text-collapsed {
|
|
95
|
+
display: none;
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
.navigation-item-counter {
|
|
92
99
|
margin-right: @spacing-1;
|
|
93
100
|
}
|
|
@@ -190,7 +197,7 @@
|
|
|
190
197
|
}
|
|
191
198
|
|
|
192
199
|
.navigation-item-counter {
|
|
193
|
-
color: @color-
|
|
200
|
+
color: @color-black;
|
|
194
201
|
font-weight: @font-weight-semibold;
|
|
195
202
|
min-width: 12px !important;
|
|
196
203
|
min-height: 12px !important;
|
|
@@ -9,7 +9,8 @@ export const navigationItemCounter: string;
|
|
|
9
9
|
export const navigationItemGroupToggle: string;
|
|
10
10
|
export const navigationItemIconSwitch: string;
|
|
11
11
|
export const navigationItemIconWrapper: string;
|
|
12
|
-
export const
|
|
12
|
+
export const navigationItemTextCollapsed: string;
|
|
13
|
+
export const navigationItemTextExpanded: string;
|
|
13
14
|
export const navigationItemTextSmall: string;
|
|
14
15
|
export const optionsIcon: string;
|
|
15
16
|
export const optionsIconWrapper: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { Popover } from '@servicetitan/anvil2';
|
|
1
2
|
import { Page } from '@servicetitan/design-system';
|
|
2
|
-
import { ComponentType, useState } from 'react';
|
|
3
|
+
import { ComponentType, FC, useState } from 'react';
|
|
3
4
|
import {
|
|
4
5
|
LocationInfo,
|
|
5
6
|
items,
|
|
@@ -7,7 +8,13 @@ import {
|
|
|
7
8
|
withDefaultRedirects,
|
|
8
9
|
withMemoryRouter,
|
|
9
10
|
} from '../../test/data';
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
SideNavigation,
|
|
13
|
+
SideNavigationExpandedState,
|
|
14
|
+
SideNavigationLink,
|
|
15
|
+
SideNavigationLinkWrapperProps,
|
|
16
|
+
SideNavigationTrigger,
|
|
17
|
+
} from './';
|
|
11
18
|
|
|
12
19
|
const layout = (Story: ComponentType) => {
|
|
13
20
|
return (
|
|
@@ -50,8 +57,11 @@ export const DefaultSideNavigation = () => {
|
|
|
50
57
|
items.pointOfSale,
|
|
51
58
|
items.reports,
|
|
52
59
|
]}
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
>
|
|
61
|
+
<SideNavigation.Top>
|
|
62
|
+
<SideNavigationLink {...items.tasks} />
|
|
63
|
+
</SideNavigation.Top>
|
|
64
|
+
</SideNavigation>
|
|
55
65
|
);
|
|
56
66
|
};
|
|
57
67
|
|
|
@@ -106,3 +116,47 @@ export const SideNavigationWithSubmenu = () => {
|
|
|
106
116
|
/>
|
|
107
117
|
);
|
|
108
118
|
};
|
|
119
|
+
|
|
120
|
+
const SideLinkPopoverWrapper: FC<SideNavigationLinkWrapperProps> = ({ children, context }) => {
|
|
121
|
+
return (
|
|
122
|
+
<Popover placement="right" openOnHover>
|
|
123
|
+
<Popover.Trigger>{props => <div {...props}>{children}</div>}</Popover.Trigger>
|
|
124
|
+
<Popover.Content style={context.styles.popoverContent}>popover content</Popover.Content>
|
|
125
|
+
</Popover>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export const SideNavigationWithCustomTopElements = () => {
|
|
130
|
+
const [expanded, setExpanded] = useState<SideNavigationExpandedState | undefined>(undefined);
|
|
131
|
+
return (
|
|
132
|
+
<SideNavigation
|
|
133
|
+
expanded={expanded}
|
|
134
|
+
onExpandedChange={setExpanded}
|
|
135
|
+
items={[
|
|
136
|
+
items.dashboard,
|
|
137
|
+
items.schedule,
|
|
138
|
+
items.dispatch,
|
|
139
|
+
|
|
140
|
+
items.accountingWithSubmenu,
|
|
141
|
+
items.purchasingWithSubmenu,
|
|
142
|
+
|
|
143
|
+
items.followUpsWithSubmenu,
|
|
144
|
+
items.reports,
|
|
145
|
+
items.marketing,
|
|
146
|
+
items.priceBook,
|
|
147
|
+
|
|
148
|
+
items.projects,
|
|
149
|
+
]}
|
|
150
|
+
>
|
|
151
|
+
<SideNavigation.Top>
|
|
152
|
+
<SideNavigationLink {...items.calls} />
|
|
153
|
+
<SideNavigationLink {...items.tasks} />
|
|
154
|
+
<SideNavigationTrigger
|
|
155
|
+
{...items.marketing}
|
|
156
|
+
isActive={false}
|
|
157
|
+
wrapper={SideLinkPopoverWrapper}
|
|
158
|
+
/>
|
|
159
|
+
</SideNavigation.Top>
|
|
160
|
+
</SideNavigation>
|
|
161
|
+
);
|
|
162
|
+
};
|