@servicetitan/navigation 11.0.0-canary.237.0c461af.0 → 11.0.0-canary.237.1f404bf.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/badge-tag.d.ts +1 -1
- package/dist/components/badge-tag.d.ts.map +1 -1
- package/dist/components/logo/logo-titan-text.d.ts +1 -1
- package/dist/components/logo/logo-titan-text.d.ts.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.module.less +2 -0
- package/dist/components/titan-layout/layout-context.js +1 -1
- package/dist/components/titan-layout/layout-context.js.map +1 -1
- package/dist/components/titan-layout/layout-header.d.ts +2 -0
- package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-header.js +3 -4
- package/dist/components/titan-layout/layout-header.js.map +1 -1
- package/dist/components/titan-layout/layout-header.module.less +55 -36
- package/dist/components/titan-layout/layout-logo.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-logo.js +2 -1
- package/dist/components/titan-layout/layout-logo.js.map +1 -1
- package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.js +20 -6
- package/dist/components/titan-layout/layout-profile.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +2 -2
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.js +2 -2
- package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links.js +10 -3
- package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.d.ts +2 -0
- package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.js +6 -4
- package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +25 -5
- package/dist/components/titan-layout/notifications-context.d.ts +13 -0
- package/dist/components/titan-layout/notifications-context.d.ts.map +1 -0
- package/dist/components/titan-layout/notifications-context.js +23 -0
- package/dist/components/titan-layout/notifications-context.js.map +1 -0
- package/dist/components/titan-layout/titan-layout.d.ts +5 -3
- package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.js +73 -28
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/components/titan-layout/titan-layout.module.less +9 -6
- package/dist/components/titan-layout/titan-layout.stories.d.ts +2 -0
- package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.stories.js +8 -5
- package/dist/components/titan-layout/titan-layout.stories.js.map +1 -1
- package/dist/test/data.d.ts +4 -1
- package/dist/test/data.d.ts.map +1 -1
- package/dist/test/data.js +2 -3
- package/dist/test/data.js.map +1 -1
- package/dist/utils/use-breakpoint.d.ts +1 -0
- package/dist/utils/use-breakpoint.d.ts.map +1 -1
- package/dist/utils/use-breakpoint.js +3 -2
- package/dist/utils/use-breakpoint.js.map +1 -1
- package/package.json +2 -2
- package/src/components/badge-tag.tsx +1 -1
- package/src/components/logo/logo-titan-text.tsx +1 -1
- package/src/components/profile-dropdown/profile-dropdown.module.less +2 -0
- package/src/components/titan-layout/layout-context.tsx +1 -1
- package/src/components/titan-layout/layout-header.module.less +55 -36
- package/src/components/titan-layout/layout-header.module.less.d.ts +2 -0
- package/src/components/titan-layout/layout-header.tsx +12 -5
- package/src/components/titan-layout/layout-logo.tsx +13 -6
- package/src/components/titan-layout/layout-profile.tsx +41 -20
- package/src/components/titan-layout/layout-sidebar-links-internal.tsx +6 -3
- package/src/components/titan-layout/layout-sidebar-links.tsx +16 -3
- package/src/components/titan-layout/layout-sidebar.module.less +25 -5
- package/src/components/titan-layout/layout-sidebar.module.less.d.ts +1 -0
- package/src/components/titan-layout/layout-sidebar.tsx +14 -5
- package/src/components/titan-layout/notifications-context.tsx +44 -0
- package/src/components/titan-layout/titan-layout.module.less +9 -6
- package/src/components/titan-layout/titan-layout.module.less.d.ts +1 -0
- package/src/components/titan-layout/titan-layout.stories.tsx +13 -4
- package/src/components/titan-layout/titan-layout.tsx +203 -107
- package/src/test/data.tsx +2 -3
- package/src/utils/use-breakpoint.ts +3 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FC,
|
|
3
|
+
PropsWithChildren,
|
|
4
|
+
createContext,
|
|
5
|
+
useCallback,
|
|
6
|
+
useContext,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
10
|
+
|
|
11
|
+
interface NotificationsContextType {
|
|
12
|
+
onNotificationsUpdate: (id: string, hasNotifications: boolean) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const NotificationsContext = createContext<NotificationsContextType>({
|
|
16
|
+
onNotificationsUpdate: () => {},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const useNotificationsContext = () => useContext(NotificationsContext);
|
|
20
|
+
|
|
21
|
+
export const useNotificationsState = () => {
|
|
22
|
+
const [hasNotifications, setHasNotifications] = useState(false);
|
|
23
|
+
const items = useRef(new Set<string>());
|
|
24
|
+
const onNotificationsUpdate = useCallback((id: string, hasNotifications: boolean) => {
|
|
25
|
+
if (hasNotifications && !items.current.has(id)) {
|
|
26
|
+
items.current.add(id);
|
|
27
|
+
setHasNotifications(!!items.current.size);
|
|
28
|
+
} else if (!hasNotifications && items.current.has(id)) {
|
|
29
|
+
items.current.delete(id);
|
|
30
|
+
setHasNotifications(!!items.current.size);
|
|
31
|
+
}
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
const NotificationsContextProvider: FC<PropsWithChildren> = useCallback(
|
|
35
|
+
({ children }) => (
|
|
36
|
+
<NotificationsContext.Provider value={{ onNotificationsUpdate }}>
|
|
37
|
+
{children}
|
|
38
|
+
</NotificationsContext.Provider>
|
|
39
|
+
),
|
|
40
|
+
[onNotificationsUpdate]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return { NotificationsContextProvider, hasNotifications };
|
|
44
|
+
};
|
|
@@ -53,18 +53,21 @@
|
|
|
53
53
|
|
|
54
54
|
.layout-legacy,
|
|
55
55
|
.layout-anvil2 {
|
|
56
|
-
overflow-x: auto;
|
|
57
56
|
.top-placeholder {
|
|
58
57
|
height: var(--nav-offset-top);
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
.layout {
|
|
63
|
-
--nav-offset-top:
|
|
62
|
+
--nav-offset-top: 0px;
|
|
63
|
+
--nav-offset-left: 0px;
|
|
64
64
|
|
|
65
|
-
&.layout-
|
|
66
|
-
--nav-offset-top:
|
|
67
|
-
|
|
65
|
+
&.layout-desktop.layout-top {
|
|
66
|
+
--nav-offset-top: 48px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&.layout-mobile.layout-top {
|
|
70
|
+
--nav-offset-top: 72px;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
&.layout-desktop.layout-nav-slim {
|
|
@@ -77,9 +80,9 @@
|
|
|
77
80
|
|
|
78
81
|
.top {
|
|
79
82
|
position: fixed;
|
|
83
|
+
width: 100vw;
|
|
80
84
|
top: 0;
|
|
81
85
|
left: 0;
|
|
82
|
-
right: 0;
|
|
83
86
|
z-index: 991;
|
|
84
87
|
}
|
|
85
88
|
|
|
@@ -9,6 +9,7 @@ export const layoutLegacy: string;
|
|
|
9
9
|
export const layoutMobile: string;
|
|
10
10
|
export const layoutNavSlim: string;
|
|
11
11
|
export const layoutNavWide: string;
|
|
12
|
+
export const layoutTop: string;
|
|
12
13
|
export const side: string;
|
|
13
14
|
export const top: string;
|
|
14
15
|
export const topPlaceholder: string;
|
|
@@ -27,6 +27,8 @@ interface LayoutContentArgs {
|
|
|
27
27
|
search: boolean;
|
|
28
28
|
longContent: boolean;
|
|
29
29
|
wideContent: boolean;
|
|
30
|
+
minWidth: boolean;
|
|
31
|
+
emptyNav: boolean;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export default {
|
|
@@ -41,6 +43,8 @@ export default {
|
|
|
41
43
|
search: true,
|
|
42
44
|
longContent: true,
|
|
43
45
|
wideContent: false,
|
|
46
|
+
minWidth: false,
|
|
47
|
+
emptyNav: false,
|
|
44
48
|
} as LayoutContentArgs,
|
|
45
49
|
};
|
|
46
50
|
|
|
@@ -68,6 +72,7 @@ const profile = (
|
|
|
68
72
|
to="https://google.com"
|
|
69
73
|
tooltip="Google it"
|
|
70
74
|
target="_blank"
|
|
75
|
+
tag={{ value: true }}
|
|
71
76
|
>
|
|
72
77
|
first link
|
|
73
78
|
</ProfileDropdown.Link>
|
|
@@ -180,7 +185,9 @@ const ContentHeader = () => {
|
|
|
180
185
|
</Fragment>
|
|
181
186
|
);
|
|
182
187
|
};
|
|
183
|
-
const SearchBar = () =>
|
|
188
|
+
const SearchBar = () => (
|
|
189
|
+
<TextField size="small" placeholder="Search" className="w-100-i m-x-half-i" />
|
|
190
|
+
);
|
|
184
191
|
|
|
185
192
|
const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
|
|
186
193
|
const [state, setState] = useState<TitanLayoutState | undefined>(undefined);
|
|
@@ -190,7 +197,7 @@ const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
|
|
|
190
197
|
onStateChange: setState,
|
|
191
198
|
|
|
192
199
|
navigationComponent: NavLinkMock,
|
|
193
|
-
navigationMainItems: mainNavItems,
|
|
200
|
+
navigationMainItems: args.emptyNav ? [] : mainNavItems,
|
|
194
201
|
|
|
195
202
|
profile,
|
|
196
203
|
top: args.search ? <SearchBar /> : undefined,
|
|
@@ -200,14 +207,16 @@ const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
|
|
|
200
207
|
extraLinksTop,
|
|
201
208
|
extraText: args.extraText ? 'EST (-8 hrs)' : undefined,
|
|
202
209
|
|
|
203
|
-
sideTop: args.sideTop ? sidebarTop() : undefined,
|
|
210
|
+
sideTop: args.sideTop && !args.emptyNav ? sidebarTop() : undefined,
|
|
211
|
+
|
|
212
|
+
minContentWidth: args.minWidth ? 900 : undefined,
|
|
204
213
|
};
|
|
205
214
|
};
|
|
206
215
|
|
|
207
216
|
const Content = (args: LayoutContentArgs) => {
|
|
208
217
|
return (
|
|
209
218
|
<Fragment>
|
|
210
|
-
<LocationInfo />
|
|
219
|
+
<LocationInfo className="m-b-3" />
|
|
211
220
|
{args.wideContent && (
|
|
212
221
|
<div style={{ width: '1200px' }}>
|
|
213
222
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
@@ -29,24 +29,27 @@ import { TitanLayoutLogo, TitanLayoutLogoProps } from './layout-logo';
|
|
|
29
29
|
import { LayoutSidebar } from './layout-sidebar';
|
|
30
30
|
import { TitanLayoutSidebarLink, TitanLayoutSidebarTrigger } from './layout-sidebar-links';
|
|
31
31
|
import { InternalSideNavigationTrigger } from './layout-sidebar-links-internal';
|
|
32
|
+
import { useNotificationsState } from './notifications-context';
|
|
32
33
|
import * as Styles from './titan-layout.module.less';
|
|
33
34
|
|
|
34
35
|
type TitanLayoutChild = ReactElement<TitanLayoutContentProps> | ReactElement<TitanLayoutLogoProps>;
|
|
35
36
|
|
|
36
37
|
export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'style'> & {
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
/** layout appearance */
|
|
39
39
|
appearance?: 'legacy' | 'anvil1' | 'anvil2';
|
|
40
40
|
|
|
41
|
+
/** layout's content */
|
|
42
|
+
children?: TitanLayoutChild | TitanLayoutChild[];
|
|
43
|
+
|
|
44
|
+
/** show only content without side and top bars */
|
|
45
|
+
contentOnly?: boolean;
|
|
46
|
+
|
|
41
47
|
/** component used for navigation */
|
|
42
48
|
navigationComponent?: FC<NavLinkComponentProps>;
|
|
43
49
|
|
|
44
50
|
/** data for main navigation links */
|
|
45
51
|
navigationMainItems?: NavigationItemData[];
|
|
46
52
|
|
|
47
|
-
/** layout's content */
|
|
48
|
-
children?: TitanLayoutChild | TitanLayoutChild[];
|
|
49
|
-
|
|
50
53
|
state?: TitanLayoutState;
|
|
51
54
|
onStateChange?: (state: TitanLayoutState) => void;
|
|
52
55
|
|
|
@@ -116,6 +119,7 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
116
119
|
appearance = 'anvil2',
|
|
117
120
|
id,
|
|
118
121
|
children,
|
|
122
|
+
contentOnly,
|
|
119
123
|
navigationComponent,
|
|
120
124
|
header,
|
|
121
125
|
top,
|
|
@@ -130,7 +134,6 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
130
134
|
sideTop,
|
|
131
135
|
}) => {
|
|
132
136
|
const breakpoint = useTitanBreakpoint();
|
|
133
|
-
const isMobile = breakpoint.isMobile;
|
|
134
137
|
const context: TitanLayoutContextType = useMemo(
|
|
135
138
|
() => ({
|
|
136
139
|
NavigationComponent: navigationComponent ?? DefaultNavLinkComponent,
|
|
@@ -143,26 +146,21 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
143
146
|
const variant = useVariant(appearance);
|
|
144
147
|
const [mobileDrawerOpened, setMobileDrawerOpened] = useState(false);
|
|
145
148
|
const { content, logo } = useLayoutChildren(children);
|
|
149
|
+
const { hasNotifications, NotificationsContextProvider } = useNotificationsState();
|
|
150
|
+
const [anvil2Styles, setAnvil2Styles] = useState<object>({});
|
|
151
|
+
const updateIndicatorsHeight = useCallback((offset: number) => {
|
|
152
|
+
setAnvil2Styles({ '--offset': `calc(var(--nav-offset-top) + ${offset}px)` });
|
|
153
|
+
}, []);
|
|
146
154
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const listener = () => {
|
|
154
|
-
setMobileDrawerOpened(false);
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
document.addEventListener('click', listener);
|
|
158
|
-
|
|
159
|
-
return () => document.removeEventListener('click', listener);
|
|
160
|
-
}, [isMobile]);
|
|
155
|
+
const isMobile = breakpoint.isMobile;
|
|
156
|
+
const hasSideBar = !contentOnly && (!!navigationMainItems?.length || !!sideTop?.length);
|
|
157
|
+
const hasTopBar = !contentOnly;
|
|
161
158
|
|
|
162
159
|
useEffect(() => {
|
|
163
160
|
if (variant.isAnvil1) {
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
const bodyClassName = 'of-hidden-i';
|
|
162
|
+
document.body.classList.add(bodyClassName);
|
|
163
|
+
return () => document.body.classList.remove(bodyClassName);
|
|
166
164
|
}
|
|
167
165
|
}, [variant.isAnvil1]);
|
|
168
166
|
|
|
@@ -190,6 +188,48 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
190
188
|
},
|
|
191
189
|
[state, onStateChange]
|
|
192
190
|
);
|
|
191
|
+
const hasMenuNotifications = useMemo(() => {
|
|
192
|
+
try {
|
|
193
|
+
return (
|
|
194
|
+
navigationMainItems?.some(item => {
|
|
195
|
+
if (item.counter || item.tag?.value) {
|
|
196
|
+
return true;
|
|
197
|
+
} else if (item.submenu) {
|
|
198
|
+
return item.submenu.groups.some(group =>
|
|
199
|
+
group.links.some(link => !!link.counter || !!link.tag?.value)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}) ?? false
|
|
204
|
+
);
|
|
205
|
+
} catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}, [navigationMainItems]);
|
|
209
|
+
|
|
210
|
+
const limitContentWidth = useMemo(() => {
|
|
211
|
+
if (variant.isAnvil2 || !minContentWidth) {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (breakpoint.width < minContentWidth) {
|
|
216
|
+
return minContentWidth;
|
|
217
|
+
}
|
|
218
|
+
}, [variant, minContentWidth, breakpoint.width]);
|
|
219
|
+
|
|
220
|
+
const contentStyles = useMemo(() => {
|
|
221
|
+
if (variant.isAnvil2) {
|
|
222
|
+
return anvil2Styles;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (variant.isLegacy && limitContentWidth) {
|
|
226
|
+
return {
|
|
227
|
+
display: 'flex',
|
|
228
|
+
flexDirection: 'column',
|
|
229
|
+
minHeight: '100vh',
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}, [variant, anvil2Styles, limitContentWidth]);
|
|
193
233
|
|
|
194
234
|
const layoutClass = variant.isLegacy
|
|
195
235
|
? Styles.layoutLegacy
|
|
@@ -205,67 +245,88 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
205
245
|
className={classNames(
|
|
206
246
|
Styles.layout,
|
|
207
247
|
isMobile ? Styles.layoutMobile : Styles.layoutDesktop,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
:
|
|
248
|
+
{
|
|
249
|
+
[Styles.layoutTop]: hasTopBar,
|
|
250
|
+
[Styles.layoutNavSlim]: !isMobile && hasSideBar && state?.navCollapsed,
|
|
251
|
+
[Styles.layoutNavWide]: !isMobile && hasSideBar && !state?.navCollapsed,
|
|
252
|
+
},
|
|
211
253
|
layoutClass
|
|
212
254
|
)}
|
|
255
|
+
style={contentStyles}
|
|
213
256
|
>
|
|
214
257
|
{variant.isSequent && <div className={Styles.topPlaceholder} />}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
{extraLinksTop}
|
|
224
|
-
{!isMobile && extraLinks}
|
|
225
|
-
</Fragment>
|
|
226
|
-
}
|
|
227
|
-
onBurgerClick={onBurgerClick}
|
|
228
|
-
/>
|
|
229
|
-
|
|
230
|
-
<LayoutSidebar
|
|
231
|
-
className={Styles.side}
|
|
232
|
-
mobile={breakpoint.isMobile}
|
|
233
|
-
barExpanded={isMobile ? mobileDrawerOpened : !state?.navCollapsed}
|
|
234
|
-
submenuExpanded={state?.submenuExpanded}
|
|
235
|
-
onBarExpandChange={onBarExpandChange}
|
|
236
|
-
onSubmenuExpandChange={onSubmenuExpandChange}
|
|
237
|
-
top={sideTop}
|
|
238
|
-
mainItems={navigationMainItems}
|
|
239
|
-
navigationComponent={context.NavigationComponent}
|
|
240
|
-
bottom={
|
|
241
|
-
isMobile ? (
|
|
258
|
+
{hasTopBar && (
|
|
259
|
+
<LayoutHeader
|
|
260
|
+
className={Styles.top}
|
|
261
|
+
logo={logo}
|
|
262
|
+
profile={isMobile ? undefined : profile}
|
|
263
|
+
center={top}
|
|
264
|
+
rightText={isMobile ? undefined : extraText}
|
|
265
|
+
right={
|
|
242
266
|
<Fragment>
|
|
243
|
-
{
|
|
244
|
-
{extraLinks}
|
|
245
|
-
{!!extraText && (
|
|
246
|
-
<InternalSideNavigationTrigger
|
|
247
|
-
id="__extra_text"
|
|
248
|
-
title={extraText}
|
|
249
|
-
submenuExpanded={undefined}
|
|
250
|
-
dataPrefix="navigation-extra-text"
|
|
251
|
-
tag={undefined}
|
|
252
|
-
icon={undefined}
|
|
253
|
-
iconActive={undefined}
|
|
254
|
-
/>
|
|
255
|
-
)}
|
|
267
|
+
{extraLinksTop}
|
|
268
|
+
{!isMobile && extraLinks}
|
|
256
269
|
</Fragment>
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
270
|
+
}
|
|
271
|
+
isMobile={isMobile}
|
|
272
|
+
hasNotifications={hasNotifications || hasMenuNotifications}
|
|
273
|
+
onBurgerClick={onBurgerClick}
|
|
274
|
+
/>
|
|
275
|
+
)}
|
|
276
|
+
|
|
277
|
+
{hasSideBar && (
|
|
278
|
+
<NotificationsContextProvider>
|
|
279
|
+
<LayoutSidebar
|
|
280
|
+
className={Styles.side}
|
|
281
|
+
mobile={breakpoint.isMobile}
|
|
282
|
+
barExpanded={!state?.navCollapsed}
|
|
283
|
+
onBarExpandChange={onBarExpandChange}
|
|
284
|
+
submenuExpanded={state?.submenuExpanded}
|
|
285
|
+
onSubmenuExpandChange={onSubmenuExpandChange}
|
|
286
|
+
drawerOpened={mobileDrawerOpened}
|
|
287
|
+
onDrawerOpenChange={setMobileDrawerOpened}
|
|
288
|
+
top={sideTop}
|
|
289
|
+
mainItems={navigationMainItems}
|
|
290
|
+
navigationComponent={context.NavigationComponent}
|
|
291
|
+
bottom={
|
|
292
|
+
isMobile ? (
|
|
293
|
+
<Fragment>
|
|
294
|
+
{profile}
|
|
295
|
+
{extraLinks}
|
|
296
|
+
{!!extraText && (
|
|
297
|
+
<InternalSideNavigationTrigger
|
|
298
|
+
id="__extra_text"
|
|
299
|
+
title={extraText}
|
|
300
|
+
submenuExpanded={undefined}
|
|
301
|
+
dataPrefix="navigation-extra-text"
|
|
302
|
+
tag={undefined}
|
|
303
|
+
icon={undefined}
|
|
304
|
+
iconActive={undefined}
|
|
305
|
+
/>
|
|
306
|
+
)}
|
|
307
|
+
</Fragment>
|
|
308
|
+
) : undefined
|
|
309
|
+
}
|
|
310
|
+
/>
|
|
311
|
+
</NotificationsContextProvider>
|
|
312
|
+
)}
|
|
313
|
+
|
|
314
|
+
{variant.isAnvil1 ? (
|
|
315
|
+
<LayoutContentAnvil1 header={header} minWidth={limitContentWidth}>
|
|
316
|
+
{content}
|
|
317
|
+
</LayoutContentAnvil1>
|
|
318
|
+
) : variant.isLegacy ? (
|
|
319
|
+
<LayoutContentLegacy header={header} minWidth={limitContentWidth}>
|
|
320
|
+
{content}
|
|
321
|
+
</LayoutContentLegacy>
|
|
322
|
+
) : (
|
|
323
|
+
<LayoutContentAnvil2
|
|
324
|
+
header={header}
|
|
325
|
+
onHeaderHeightChange={updateIndicatorsHeight}
|
|
326
|
+
>
|
|
327
|
+
{content}
|
|
328
|
+
</LayoutContentAnvil2>
|
|
329
|
+
)}
|
|
269
330
|
</div>
|
|
270
331
|
</LayoutPlacementContext.Provider>
|
|
271
332
|
</LayoutContext.Provider>
|
|
@@ -306,57 +367,92 @@ const TitanLayoutHeaderObserved: FC<{
|
|
|
306
367
|
</div>
|
|
307
368
|
);
|
|
308
369
|
};
|
|
370
|
+
const TitanLayoutHeader: FC<{ children: ReactNode }> = ({ children }) => {
|
|
371
|
+
return (
|
|
372
|
+
<div className={Styles.contentHeader} data-cy="layout-content-header">
|
|
373
|
+
{children}
|
|
374
|
+
</div>
|
|
375
|
+
);
|
|
376
|
+
};
|
|
309
377
|
|
|
310
378
|
export interface TitanLayoutContentProps {
|
|
311
379
|
children: ReactNode;
|
|
312
380
|
}
|
|
313
381
|
const TitanLayoutContent: FC<TitanLayoutContentProps> = ({ children }) => children;
|
|
314
382
|
|
|
315
|
-
const
|
|
383
|
+
const LayoutContentAnvil2: FC<{
|
|
316
384
|
children: ReactNode;
|
|
317
385
|
header?: ReactNode;
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
386
|
+
onHeaderHeightChange?: (height: number) => void;
|
|
387
|
+
}> = ({ children, header, onHeaderHeightChange }) => {
|
|
388
|
+
return (
|
|
389
|
+
<Fragment>
|
|
390
|
+
<TitanLayoutHeaderObserved heightChange={onHeaderHeightChange}>
|
|
391
|
+
{header}
|
|
392
|
+
</TitanLayoutHeaderObserved>
|
|
393
|
+
{children}
|
|
394
|
+
</Fragment>
|
|
395
|
+
);
|
|
396
|
+
};
|
|
326
397
|
|
|
327
|
-
|
|
398
|
+
const LayoutContentAnvil1: FC<{
|
|
399
|
+
children: ReactNode;
|
|
400
|
+
header?: ReactNode;
|
|
401
|
+
minWidth?: number;
|
|
402
|
+
}> = ({ children, header, minWidth }) => {
|
|
403
|
+
const innerContentStyles: CSSProperties = useMemo(
|
|
328
404
|
() => ({
|
|
329
405
|
...(minWidth ? { minWidth: `${minWidth}px` } : {}),
|
|
330
|
-
...(anvil2 ? anvil2Styles : {}),
|
|
331
406
|
}),
|
|
332
|
-
[
|
|
407
|
+
[minWidth]
|
|
333
408
|
);
|
|
334
409
|
|
|
335
410
|
return (
|
|
336
411
|
<Fragment>
|
|
337
|
-
{
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
{anvil1 ? (
|
|
349
|
-
<div className="position-relative d-f flex-grow-1 flex-basis-0 of-hidden">
|
|
350
|
-
{children}
|
|
351
|
-
</div>
|
|
352
|
-
) : (
|
|
353
|
-
children
|
|
354
|
-
)}
|
|
412
|
+
<TitanLayoutHeader>{header}</TitanLayoutHeader>
|
|
413
|
+
<div
|
|
414
|
+
className={classNames(Styles.content, { 'of-x-auto': !!minWidth })}
|
|
415
|
+
data-cy="layout-content"
|
|
416
|
+
>
|
|
417
|
+
<div
|
|
418
|
+
className="position-relative d-f flex-grow-1 flex-basis-0 of-hidden"
|
|
419
|
+
style={innerContentStyles}
|
|
420
|
+
>
|
|
421
|
+
{children}
|
|
422
|
+
</div>
|
|
355
423
|
</div>
|
|
356
424
|
</Fragment>
|
|
357
425
|
);
|
|
358
426
|
};
|
|
359
427
|
|
|
428
|
+
const LayoutContentLegacy: FC<{
|
|
429
|
+
children: ReactNode;
|
|
430
|
+
header?: ReactNode;
|
|
431
|
+
minWidth: number | undefined;
|
|
432
|
+
}> = ({ children, header, minWidth }) => {
|
|
433
|
+
const innerContentStyles: CSSProperties = useMemo(
|
|
434
|
+
() => ({
|
|
435
|
+
position: 'relative',
|
|
436
|
+
minWidth: `${minWidth}px`,
|
|
437
|
+
}),
|
|
438
|
+
[minWidth]
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
return (
|
|
442
|
+
<Fragment>
|
|
443
|
+
<TitanLayoutHeader>{header}</TitanLayoutHeader>
|
|
444
|
+
|
|
445
|
+
{minWidth ? (
|
|
446
|
+
<div className="of-x-auto flex-basis-0 flex-grow-1">
|
|
447
|
+
<div style={innerContentStyles}>{children}</div>
|
|
448
|
+
</div>
|
|
449
|
+
) : (
|
|
450
|
+
children
|
|
451
|
+
)}
|
|
452
|
+
</Fragment>
|
|
453
|
+
);
|
|
454
|
+
};
|
|
455
|
+
|
|
360
456
|
export const TitanLayout = Object.assign(TitanLayoutComponent, {
|
|
361
457
|
Content: TitanLayoutContent,
|
|
362
458
|
Logo: TitanLayoutLogo,
|
package/src/test/data.tsx
CHANGED
|
@@ -66,7 +66,6 @@ export const NavLinkMock = forwardRef<any, NavLinkComponentProps>(
|
|
|
66
66
|
{...rest}
|
|
67
67
|
onClick={e => {
|
|
68
68
|
e.preventDefault();
|
|
69
|
-
e.stopPropagation();
|
|
70
69
|
|
|
71
70
|
if (!to.startsWith('http')) {
|
|
72
71
|
history.replace(to);
|
|
@@ -82,10 +81,10 @@ export const NavLinkMock = forwardRef<any, NavLinkComponentProps>(
|
|
|
82
81
|
}
|
|
83
82
|
);
|
|
84
83
|
|
|
85
|
-
export const LocationInfo = () => {
|
|
84
|
+
export const LocationInfo: FC<{ className?: string }> = ({ className }) => {
|
|
86
85
|
const location = useLocation();
|
|
87
86
|
|
|
88
|
-
return <BodyText>current location - {location.pathname}</BodyText>;
|
|
87
|
+
return <BodyText className={className}>current location - {location.pathname}</BodyText>;
|
|
89
88
|
};
|
|
90
89
|
|
|
91
90
|
const LocationProvider: FC<{ children: any }> = ({ children }) => {
|
|
@@ -4,6 +4,7 @@ import { useMemo } from 'react';
|
|
|
4
4
|
export interface TitanBreakpoint {
|
|
5
5
|
name: BreakpointReturnProps['name'];
|
|
6
6
|
isMobile: boolean;
|
|
7
|
+
width: number;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export const useTitanBreakpoint = (): TitanBreakpoint => {
|
|
@@ -12,7 +13,8 @@ export const useTitanBreakpoint = (): TitanBreakpoint => {
|
|
|
12
13
|
return useMemo(
|
|
13
14
|
() => ({
|
|
14
15
|
name: breakpoint?.name ?? 'xl',
|
|
15
|
-
isMobile: breakpoint ? breakpoint.innerWidth
|
|
16
|
+
isMobile: breakpoint ? breakpoint.innerWidth < 768 : false,
|
|
17
|
+
width: breakpoint?.innerWidth ?? 0,
|
|
16
18
|
}),
|
|
17
19
|
[breakpoint]
|
|
18
20
|
);
|