@servicetitan/navigation 11.0.0-canary.237.0ce6038.0 → 11.0.0-canary.237.2d7cfa1.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/header-navigation/header-navigation-stacked.stories.js +1 -1
- package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +1 -1
- package/dist/components/header-navigation/header-navigation.stories.js +1 -1
- package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
- package/dist/components/left-navigation/header-navigation-tiny.stories.js +2 -2
- package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.d.ts +10 -7
- package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
- package/dist/components/profile-dropdown/profile-dropdown.js +2 -2
- package/dist/components/profile-dropdown/profile-dropdown.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 +57 -15
- package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.js +32 -8
- package/dist/components/titan-layout/layout-profile.js.map +1 -1
- package/dist/components/titan-layout/layout-profile.stories.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-profile.stories.js +1 -1
- package/dist/components/titan-layout/layout-profile.stories.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 +4 -4
- 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 +11 -4
- 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 +20 -4
- 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 +68 -20
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/components/titan-layout/titan-layout.module.less +43 -16
- package/dist/components/titan-layout/titan-layout.stories.d.ts +14 -11
- package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.stories.js +33 -13
- 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/package.json +2 -2
- package/src/components/badge-tag.tsx +1 -1
- package/src/components/header-navigation/header-navigation-stacked.stories.tsx +1 -1
- package/src/components/header-navigation/header-navigation.stories.tsx +1 -1
- package/src/components/left-navigation/header-navigation-tiny.stories.tsx +2 -2
- package/src/components/profile-dropdown/profile-dropdown.tsx +13 -6
- package/src/components/titan-layout/layout-header.module.less +57 -15
- package/src/components/titan-layout/layout-header.tsx +12 -5
- package/src/components/titan-layout/layout-profile.stories.tsx +10 -1
- package/src/components/titan-layout/layout-profile.tsx +60 -25
- package/src/components/titan-layout/layout-sidebar-links-internal.tsx +18 -5
- package/src/components/titan-layout/layout-sidebar-links.tsx +16 -4
- package/src/components/titan-layout/layout-sidebar.module.less +20 -4
- 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 +43 -16
- package/src/components/titan-layout/titan-layout.module.less.d.ts +2 -0
- package/src/components/titan-layout/titan-layout.stories.tsx +161 -18
- package/src/components/titan-layout/titan-layout.tsx +164 -60
- package/src/test/data.tsx +2 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Page as Anvil2Page, Popover } from '@servicetitan/anvil2';
|
|
1
|
+
import { Announcement, Page as Anvil2Page, Button, Popover, TextField } from '@servicetitan/anvil2';
|
|
2
2
|
import SvgSearch from '@servicetitan/anvil2/assets/icons/material/round/search.svg';
|
|
3
3
|
import SvgAtlas from '@servicetitan/anvil2/assets/icons/st/atlas_logo.svg';
|
|
4
4
|
import SvgSettingsActive from '@servicetitan/anvil2/assets/icons/st/gnav_settings_active.svg';
|
|
@@ -20,11 +20,30 @@ import { SideNavigationLinkWrapperProps } from '../left-navigation';
|
|
|
20
20
|
import { HeaderNavigationLink, HeaderNavigationTrigger } from '../links';
|
|
21
21
|
import { ProfileDropdown, TitanLayout, TitanLayoutProps, TitanLayoutState } from './';
|
|
22
22
|
|
|
23
|
+
interface LayoutContentArgs {
|
|
24
|
+
header: boolean;
|
|
25
|
+
sideTop: boolean;
|
|
26
|
+
extraText: boolean;
|
|
27
|
+
search: boolean;
|
|
28
|
+
longContent: boolean;
|
|
29
|
+
wideContent: boolean;
|
|
30
|
+
minWidth: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
export default {
|
|
24
34
|
title: 'Navigation/TitanLayout',
|
|
25
|
-
component: TitanLayout,
|
|
26
35
|
decorators: [withDefaultRedirects, withMemoryRouter, withAnvil],
|
|
27
36
|
parameters: {},
|
|
37
|
+
argTypes: {},
|
|
38
|
+
args: {
|
|
39
|
+
header: true,
|
|
40
|
+
sideTop: true,
|
|
41
|
+
extraText: true,
|
|
42
|
+
search: true,
|
|
43
|
+
longContent: true,
|
|
44
|
+
wideContent: false,
|
|
45
|
+
minWidth: false,
|
|
46
|
+
} as LayoutContentArgs,
|
|
28
47
|
};
|
|
29
48
|
|
|
30
49
|
const mainNavItems = [
|
|
@@ -51,6 +70,7 @@ const profile = (
|
|
|
51
70
|
to="https://google.com"
|
|
52
71
|
tooltip="Google it"
|
|
53
72
|
target="_blank"
|
|
73
|
+
tag={{ value: true }}
|
|
54
74
|
>
|
|
55
75
|
first link
|
|
56
76
|
</ProfileDropdown.Link>
|
|
@@ -131,9 +151,9 @@ const SideLinkPopoverWrapper: FC<SideNavigationLinkWrapperProps> = ({ children,
|
|
|
131
151
|
};
|
|
132
152
|
|
|
133
153
|
const sidebarTop = () => [
|
|
134
|
-
<TitanLayout.
|
|
135
|
-
<TitanLayout.
|
|
136
|
-
<TitanLayout.
|
|
154
|
+
<TitanLayout.Link key="tasks" {...items.tasks} />,
|
|
155
|
+
<TitanLayout.Link key="calls" {...items.calls} />,
|
|
156
|
+
<TitanLayout.Trigger
|
|
137
157
|
key="marketing"
|
|
138
158
|
{...items.marketing}
|
|
139
159
|
isActive={false}
|
|
@@ -142,51 +162,174 @@ const sidebarTop = () => [
|
|
|
142
162
|
counter={50}
|
|
143
163
|
/>,
|
|
144
164
|
];
|
|
145
|
-
const
|
|
165
|
+
const ContentHeader = () => {
|
|
166
|
+
const [longInfo, setLongInfo] = useState(false);
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<Fragment>
|
|
170
|
+
<Announcement title="Some info" status="info" />
|
|
171
|
+
<Announcement title="Some warning" status="warning" />
|
|
172
|
+
<div
|
|
173
|
+
className="d-f justify-content-center align-items-center bg-purple-100-i"
|
|
174
|
+
style={{ height: longInfo ? '120px' : '48px' }}
|
|
175
|
+
>
|
|
176
|
+
<div className="d-f align-items-center gap-1">
|
|
177
|
+
custom content{' '}
|
|
178
|
+
<Button onClick={() => setLongInfo(!longInfo)} size="small" aria-label="test">
|
|
179
|
+
{longInfo ? '↑' : '↓'}
|
|
180
|
+
</Button>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</Fragment>
|
|
184
|
+
);
|
|
185
|
+
};
|
|
186
|
+
const SearchBar = () => <TextField size="small" placeholder="Search" className="w-100-i" />;
|
|
187
|
+
|
|
188
|
+
const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
|
|
146
189
|
const [state, setState] = useState<TitanLayoutState | undefined>(undefined);
|
|
147
190
|
|
|
148
191
|
return {
|
|
149
192
|
state,
|
|
150
193
|
onStateChange: setState,
|
|
151
194
|
|
|
195
|
+
navigationComponent: NavLinkMock,
|
|
152
196
|
navigationMainItems: mainNavItems,
|
|
197
|
+
|
|
153
198
|
profile,
|
|
199
|
+
top: args.search ? <SearchBar /> : undefined,
|
|
200
|
+
header: args.header ? <ContentHeader /> : undefined,
|
|
201
|
+
|
|
154
202
|
extraLinks,
|
|
155
203
|
extraLinksTop,
|
|
204
|
+
extraText: args.extraText ? 'EST (-8 hrs)' : undefined,
|
|
156
205
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
206
|
+
sideTop: args.sideTop ? sidebarTop() : undefined,
|
|
207
|
+
|
|
208
|
+
minContentWidth: args.minWidth ? 900 : undefined,
|
|
160
209
|
};
|
|
161
210
|
};
|
|
162
211
|
|
|
163
|
-
|
|
164
|
-
|
|
212
|
+
const Content = (args: LayoutContentArgs) => {
|
|
213
|
+
return (
|
|
214
|
+
<Fragment>
|
|
215
|
+
<LocationInfo className="m-b-3" />
|
|
216
|
+
{args.wideContent && (
|
|
217
|
+
<div style={{ width: '1200px' }}>
|
|
218
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
219
|
+
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
|
|
220
|
+
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
|
221
|
+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
|
|
222
|
+
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
|
|
223
|
+
culpa qui officia deserunt mollit anim id est laborum.
|
|
224
|
+
</div>
|
|
225
|
+
)}
|
|
226
|
+
|
|
227
|
+
{args.longContent && (
|
|
228
|
+
<div>
|
|
229
|
+
<p>Lorem</p>
|
|
230
|
+
<p>ipsum</p>
|
|
231
|
+
<p>dolor</p>
|
|
232
|
+
<p>sit</p>
|
|
233
|
+
<p>amet,</p>
|
|
234
|
+
<p>consectetur</p>
|
|
235
|
+
<p>adipiscing</p>
|
|
236
|
+
<p>elit,</p>
|
|
237
|
+
<p>sed</p>
|
|
238
|
+
<p>do</p>
|
|
239
|
+
<p>eiusmod</p>
|
|
240
|
+
<p>tempor</p>
|
|
241
|
+
<p>incididunt</p>
|
|
242
|
+
<p>ut</p>
|
|
243
|
+
<p>labore</p>
|
|
244
|
+
<p>et</p>
|
|
245
|
+
<p>dolore</p>
|
|
246
|
+
<p>magna</p>
|
|
247
|
+
<p>aliqua.</p>
|
|
248
|
+
<p>Ut</p>
|
|
249
|
+
<p>enim</p>
|
|
250
|
+
<p>ad</p>
|
|
251
|
+
<p>minim</p>
|
|
252
|
+
<p>veniam,</p>
|
|
253
|
+
<p>quis</p>
|
|
254
|
+
<p>nostrud</p>
|
|
255
|
+
<p>exercitation</p>
|
|
256
|
+
<p>ullamco</p>
|
|
257
|
+
<p>laboris</p>
|
|
258
|
+
<p>nisi</p>
|
|
259
|
+
<p>ut</p>
|
|
260
|
+
<p>aliquip</p>
|
|
261
|
+
<p>ex</p>
|
|
262
|
+
<p>ea</p>
|
|
263
|
+
<p>commodo</p>
|
|
264
|
+
<p>consequat.</p>
|
|
265
|
+
<p>Duis</p>
|
|
266
|
+
<p>aute</p>
|
|
267
|
+
<p>irure</p>
|
|
268
|
+
<p>dolor</p>
|
|
269
|
+
<p>in</p>
|
|
270
|
+
<p>reprehenderit</p>
|
|
271
|
+
<p>in</p>
|
|
272
|
+
<p>voluptate</p>
|
|
273
|
+
<p>velit</p>
|
|
274
|
+
<p>esse</p>
|
|
275
|
+
<p>cillum</p>
|
|
276
|
+
<p>dolore</p>
|
|
277
|
+
<p>eu</p>
|
|
278
|
+
<p>fugiat</p>
|
|
279
|
+
<p>nulla</p>
|
|
280
|
+
<p>pariatur.</p>
|
|
281
|
+
<p>Excepteur</p>
|
|
282
|
+
<p>sint</p>
|
|
283
|
+
<p>occaecat</p>
|
|
284
|
+
<p>cupidatat</p>
|
|
285
|
+
<p>non</p>
|
|
286
|
+
<p>proident,</p>
|
|
287
|
+
<p>sunt</p>
|
|
288
|
+
<p>in</p>
|
|
289
|
+
<p>culpa</p>
|
|
290
|
+
<p>qui</p>
|
|
291
|
+
<p>officia</p>
|
|
292
|
+
<p>deserunt</p>
|
|
293
|
+
<p>mollit</p>
|
|
294
|
+
<p>anim</p>
|
|
295
|
+
<p>id</p>
|
|
296
|
+
<p>est</p>
|
|
297
|
+
<p>laborum.</p>
|
|
298
|
+
</div>
|
|
299
|
+
)}
|
|
300
|
+
</Fragment>
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export const TitanLayoutLegacy = (args: LayoutContentArgs) => (
|
|
305
|
+
<TitanLayout {...useLayoutProps(args)} appearance="legacy">
|
|
165
306
|
<TitanLayout.Logo title />
|
|
166
307
|
<TitanLayout.Content>
|
|
167
|
-
<
|
|
308
|
+
<div className="p-3">
|
|
309
|
+
<Content {...args} />
|
|
310
|
+
</div>
|
|
168
311
|
</TitanLayout.Content>
|
|
169
312
|
</TitanLayout>
|
|
170
313
|
);
|
|
171
314
|
|
|
172
|
-
export const TitanLayoutAnvil1 = () => (
|
|
173
|
-
<TitanLayout {...useLayoutProps()} appearance="anvil1">
|
|
315
|
+
export const TitanLayoutAnvil1 = (args: LayoutContentArgs) => (
|
|
316
|
+
<TitanLayout {...useLayoutProps(args)} appearance="anvil1">
|
|
174
317
|
<TitanLayout.Logo title />
|
|
175
318
|
<TitanLayout.Content>
|
|
176
319
|
<Anvil1Page>
|
|
177
|
-
<
|
|
320
|
+
<Content {...args} />
|
|
178
321
|
</Anvil1Page>
|
|
179
322
|
</TitanLayout.Content>
|
|
180
323
|
</TitanLayout>
|
|
181
324
|
);
|
|
182
325
|
|
|
183
|
-
export const TitanLayoutAnvil2 = () => (
|
|
184
|
-
<TitanLayout {...useLayoutProps()} appearance="anvil2">
|
|
326
|
+
export const TitanLayoutAnvil2 = (args: LayoutContentArgs) => (
|
|
327
|
+
<TitanLayout {...useLayoutProps(args)} appearance="anvil2">
|
|
185
328
|
<TitanLayout.Logo title />
|
|
186
329
|
<TitanLayout.Content>
|
|
187
330
|
<Anvil2Page>
|
|
188
331
|
<Anvil2Page.Content>
|
|
189
|
-
<
|
|
332
|
+
<Content {...args} />
|
|
190
333
|
</Anvil2Page.Content>
|
|
191
334
|
</Anvil2Page>
|
|
192
335
|
</TitanLayout.Content>
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
useCallback,
|
|
12
12
|
useEffect,
|
|
13
13
|
useMemo,
|
|
14
|
+
useRef,
|
|
14
15
|
useState,
|
|
15
16
|
} from 'react';
|
|
16
17
|
import { NavigationItemData } from '../../utils/navigation';
|
|
@@ -28,6 +29,7 @@ import { TitanLayoutLogo, TitanLayoutLogoProps } from './layout-logo';
|
|
|
28
29
|
import { LayoutSidebar } from './layout-sidebar';
|
|
29
30
|
import { TitanLayoutSidebarLink, TitanLayoutSidebarTrigger } from './layout-sidebar-links';
|
|
30
31
|
import { InternalSideNavigationTrigger } from './layout-sidebar-links-internal';
|
|
32
|
+
import { useNotificationsState } from './notifications-context';
|
|
31
33
|
import * as Styles from './titan-layout.module.less';
|
|
32
34
|
|
|
33
35
|
type TitanLayoutChild = ReactElement<TitanLayoutContentProps> | ReactElement<TitanLayoutLogoProps>;
|
|
@@ -50,11 +52,13 @@ export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
50
52
|
onStateChange?: (state: TitanLayoutState) => void;
|
|
51
53
|
|
|
52
54
|
header?: ReactElement;
|
|
55
|
+
top?: ReactElement;
|
|
56
|
+
sideTop?: ReactElement[];
|
|
53
57
|
profile?: ReactElement;
|
|
54
58
|
extraLinks?: ReactElement;
|
|
55
59
|
extraLinksTop?: ReactElement;
|
|
56
60
|
extraText?: string;
|
|
57
|
-
|
|
61
|
+
minContentWidth?: number;
|
|
58
62
|
};
|
|
59
63
|
|
|
60
64
|
const defaultSidebarContext: TitanLayoutSidebarContextType = {
|
|
@@ -115,6 +119,7 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
115
119
|
children,
|
|
116
120
|
navigationComponent,
|
|
117
121
|
header,
|
|
122
|
+
top,
|
|
118
123
|
profile,
|
|
119
124
|
state,
|
|
120
125
|
onStateChange,
|
|
@@ -122,7 +127,8 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
122
127
|
extraLinks,
|
|
123
128
|
extraLinksTop,
|
|
124
129
|
extraText,
|
|
125
|
-
|
|
130
|
+
minContentWidth,
|
|
131
|
+
sideTop,
|
|
126
132
|
}) => {
|
|
127
133
|
const breakpoint = useTitanBreakpoint();
|
|
128
134
|
const isMobile = breakpoint.isMobile;
|
|
@@ -138,21 +144,15 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
138
144
|
const variant = useVariant(appearance);
|
|
139
145
|
const [mobileDrawerOpened, setMobileDrawerOpened] = useState(false);
|
|
140
146
|
const { content, logo } = useLayoutChildren(children);
|
|
147
|
+
const { hasNotifications, NotificationsContextProvider } = useNotificationsState();
|
|
141
148
|
|
|
142
149
|
useEffect(() => {
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
if (variant.isAnvil1) {
|
|
151
|
+
const bodyClassName = 'of-hidden-i';
|
|
152
|
+
document.body.classList.add(bodyClassName);
|
|
153
|
+
return () => document.body.classList.remove(bodyClassName);
|
|
146
154
|
}
|
|
147
|
-
|
|
148
|
-
const listener = () => {
|
|
149
|
-
setMobileDrawerOpened(false);
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
document.addEventListener('click', listener);
|
|
153
|
-
|
|
154
|
-
return () => document.removeEventListener('click', listener);
|
|
155
|
-
}, [isMobile]);
|
|
155
|
+
}, [variant.isAnvil1]);
|
|
156
156
|
|
|
157
157
|
const onBurgerClick = useCallback((e: MouseEvent) => {
|
|
158
158
|
setMobileDrawerOpened(true);
|
|
@@ -178,8 +178,24 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
178
178
|
},
|
|
179
179
|
[state, onStateChange]
|
|
180
180
|
);
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
const hasMenuNotifications = useMemo(() => {
|
|
182
|
+
try {
|
|
183
|
+
return (
|
|
184
|
+
navigationMainItems?.some(item => {
|
|
185
|
+
if (item.counter || item.tag?.value) {
|
|
186
|
+
return true;
|
|
187
|
+
} else if (item.submenu) {
|
|
188
|
+
return item.submenu.groups.some(group =>
|
|
189
|
+
group.links.some(link => !!link.counter || !!link.tag?.value)
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
}) ?? false
|
|
194
|
+
);
|
|
195
|
+
} catch {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}, [navigationMainItems]);
|
|
183
199
|
|
|
184
200
|
const layoutClass = variant.isLegacy
|
|
185
201
|
? Styles.layoutLegacy
|
|
@@ -194,21 +210,19 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
194
210
|
id={id}
|
|
195
211
|
className={classNames(
|
|
196
212
|
Styles.layout,
|
|
197
|
-
isMobile
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
: Styles.layoutNavWide,
|
|
213
|
+
isMobile ? Styles.layoutMobile : Styles.layoutDesktop,
|
|
214
|
+
!isMobile && state?.navCollapsed
|
|
215
|
+
? Styles.layoutNavSlim
|
|
216
|
+
: Styles.layoutNavWide,
|
|
202
217
|
layoutClass
|
|
203
218
|
)}
|
|
204
|
-
style={layoutStyles}
|
|
205
219
|
>
|
|
206
220
|
{variant.isSequent && <div className={Styles.topPlaceholder} />}
|
|
207
221
|
<LayoutHeader
|
|
208
222
|
className={Styles.top}
|
|
209
223
|
logo={logo}
|
|
210
224
|
profile={isMobile ? undefined : profile}
|
|
211
|
-
center={
|
|
225
|
+
center={top}
|
|
212
226
|
rightText={isMobile ? undefined : extraText}
|
|
213
227
|
right={
|
|
214
228
|
<Fragment>
|
|
@@ -216,57 +230,147 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
|
|
|
216
230
|
{!isMobile && extraLinks}
|
|
217
231
|
</Fragment>
|
|
218
232
|
}
|
|
233
|
+
isMobile={isMobile}
|
|
234
|
+
hasNotifications={hasNotifications || hasMenuNotifications}
|
|
219
235
|
onBurgerClick={onBurgerClick}
|
|
220
236
|
/>
|
|
221
237
|
|
|
222
|
-
<
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
238
|
+
<NotificationsContextProvider>
|
|
239
|
+
<LayoutSidebar
|
|
240
|
+
className={Styles.side}
|
|
241
|
+
mobile={breakpoint.isMobile}
|
|
242
|
+
barExpanded={!state?.navCollapsed}
|
|
243
|
+
onBarExpandChange={onBarExpandChange}
|
|
244
|
+
submenuExpanded={state?.submenuExpanded}
|
|
245
|
+
onSubmenuExpandChange={onSubmenuExpandChange}
|
|
246
|
+
drawerOpened={mobileDrawerOpened}
|
|
247
|
+
onDrawerOpenChange={setMobileDrawerOpened}
|
|
248
|
+
top={sideTop}
|
|
249
|
+
mainItems={navigationMainItems}
|
|
250
|
+
navigationComponent={context.NavigationComponent}
|
|
251
|
+
bottom={
|
|
252
|
+
isMobile ? (
|
|
253
|
+
<Fragment>
|
|
254
|
+
{profile}
|
|
255
|
+
{extraLinks}
|
|
256
|
+
{!!extraText && (
|
|
257
|
+
<InternalSideNavigationTrigger
|
|
258
|
+
id="__extra_text"
|
|
259
|
+
title={extraText}
|
|
260
|
+
submenuExpanded={undefined}
|
|
261
|
+
dataPrefix="navigation-extra-text"
|
|
262
|
+
tag={undefined}
|
|
263
|
+
icon={undefined}
|
|
264
|
+
iconActive={undefined}
|
|
265
|
+
/>
|
|
266
|
+
)}
|
|
267
|
+
</Fragment>
|
|
268
|
+
) : undefined
|
|
269
|
+
}
|
|
270
|
+
/>
|
|
271
|
+
</NotificationsContextProvider>
|
|
272
|
+
<LayoutContent
|
|
273
|
+
header={header}
|
|
274
|
+
anvil2={variant.isAnvil2}
|
|
275
|
+
anvil1={variant.isAnvil1}
|
|
276
|
+
minWidth={minContentWidth}
|
|
277
|
+
>
|
|
278
|
+
{content}
|
|
279
|
+
</LayoutContent>
|
|
254
280
|
</div>
|
|
255
281
|
</LayoutPlacementContext.Provider>
|
|
256
282
|
</LayoutContext.Provider>
|
|
257
283
|
);
|
|
258
284
|
};
|
|
259
285
|
|
|
286
|
+
const TitanLayoutHeaderObserved: FC<{
|
|
287
|
+
children: ReactNode;
|
|
288
|
+
heightChange?(value: number): void;
|
|
289
|
+
}> = ({ children, heightChange }) => {
|
|
290
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
291
|
+
|
|
292
|
+
useEffect(() => {
|
|
293
|
+
if (ref.current) {
|
|
294
|
+
const updatePosition = () => {
|
|
295
|
+
if (ref.current && heightChange) {
|
|
296
|
+
const pos = ref.current.getBoundingClientRect();
|
|
297
|
+
heightChange(pos.height);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const observer = new ResizeObserver(updatePosition);
|
|
302
|
+
observer.observe(ref.current);
|
|
303
|
+
|
|
304
|
+
updatePosition();
|
|
305
|
+
return () => observer.disconnect();
|
|
306
|
+
}
|
|
307
|
+
}, [heightChange]);
|
|
308
|
+
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
return () => {
|
|
311
|
+
heightChange?.(0);
|
|
312
|
+
};
|
|
313
|
+
}, [heightChange]);
|
|
314
|
+
return (
|
|
315
|
+
<div ref={ref} className={Styles.contentHeader} data-cy="layout-content-header">
|
|
316
|
+
{children}
|
|
317
|
+
</div>
|
|
318
|
+
);
|
|
319
|
+
};
|
|
320
|
+
|
|
260
321
|
export interface TitanLayoutContentProps {
|
|
261
322
|
children: ReactNode;
|
|
262
323
|
}
|
|
263
|
-
const TitanLayoutContent: FC<TitanLayoutContentProps> = ({ children }) =>
|
|
264
|
-
|
|
265
|
-
|
|
324
|
+
const TitanLayoutContent: FC<TitanLayoutContentProps> = ({ children }) => children;
|
|
325
|
+
|
|
326
|
+
const LayoutContent: FC<{
|
|
327
|
+
children: ReactNode;
|
|
328
|
+
header?: ReactNode;
|
|
329
|
+
anvil1: boolean;
|
|
330
|
+
anvil2: boolean;
|
|
331
|
+
minWidth: number | undefined;
|
|
332
|
+
}> = ({ anvil1, anvil2, children, header, minWidth }) => {
|
|
333
|
+
const [anvil2Styles, setAnvil2Styles] = useState<object>({});
|
|
334
|
+
const updateIndicatorsHeight = useCallback((offset: number) => {
|
|
335
|
+
setAnvil2Styles({ '--offset': `calc(var(--nav-offset-top) + ${offset}px)` });
|
|
336
|
+
}, []);
|
|
337
|
+
|
|
338
|
+
const contentStyles = useMemo(
|
|
339
|
+
() => ({
|
|
340
|
+
...(minWidth ? { minWidth: `${minWidth}px` } : {}),
|
|
341
|
+
...(anvil2 ? anvil2Styles : {}),
|
|
342
|
+
}),
|
|
343
|
+
[anvil2, minWidth, anvil2Styles]
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
return (
|
|
347
|
+
<Fragment>
|
|
348
|
+
{!!header &&
|
|
349
|
+
(anvil2 ? (
|
|
350
|
+
<TitanLayoutHeaderObserved heightChange={updateIndicatorsHeight}>
|
|
351
|
+
{header}
|
|
352
|
+
</TitanLayoutHeaderObserved>
|
|
353
|
+
) : (
|
|
354
|
+
<div className={Styles.contentHeader} data-cy="layout-content-header">
|
|
355
|
+
{header}
|
|
356
|
+
</div>
|
|
357
|
+
))}
|
|
358
|
+
<div className={Styles.content} style={contentStyles} data-cy="layout-content">
|
|
359
|
+
{anvil1 ? (
|
|
360
|
+
<div className="position-relative d-f flex-grow-1 flex-basis-0 of-hidden">
|
|
361
|
+
{children}
|
|
362
|
+
</div>
|
|
363
|
+
) : (
|
|
364
|
+
children
|
|
365
|
+
)}
|
|
366
|
+
</div>
|
|
367
|
+
</Fragment>
|
|
368
|
+
);
|
|
369
|
+
};
|
|
266
370
|
|
|
267
371
|
export const TitanLayout = Object.assign(TitanLayoutComponent, {
|
|
268
372
|
Content: TitanLayoutContent,
|
|
269
373
|
Logo: TitanLayoutLogo,
|
|
270
|
-
|
|
271
|
-
|
|
374
|
+
Link: TitanLayoutSidebarLink,
|
|
375
|
+
Trigger: TitanLayoutSidebarTrigger,
|
|
272
376
|
});
|
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 }) => {
|