@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.
Files changed (73) hide show
  1. package/dist/components/badge-tag.d.ts +1 -1
  2. package/dist/components/badge-tag.d.ts.map +1 -1
  3. package/dist/components/header-navigation/header-navigation-stacked.stories.js +1 -1
  4. package/dist/components/header-navigation/header-navigation-stacked.stories.js.map +1 -1
  5. package/dist/components/header-navigation/header-navigation.stories.js +1 -1
  6. package/dist/components/header-navigation/header-navigation.stories.js.map +1 -1
  7. package/dist/components/left-navigation/header-navigation-tiny.stories.js +2 -2
  8. package/dist/components/left-navigation/header-navigation-tiny.stories.js.map +1 -1
  9. package/dist/components/profile-dropdown/profile-dropdown.d.ts +10 -7
  10. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  11. package/dist/components/profile-dropdown/profile-dropdown.js +2 -2
  12. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  13. package/dist/components/titan-layout/layout-header.d.ts +2 -0
  14. package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
  15. package/dist/components/titan-layout/layout-header.js +3 -4
  16. package/dist/components/titan-layout/layout-header.js.map +1 -1
  17. package/dist/components/titan-layout/layout-header.module.less +57 -15
  18. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
  19. package/dist/components/titan-layout/layout-profile.js +32 -8
  20. package/dist/components/titan-layout/layout-profile.js.map +1 -1
  21. package/dist/components/titan-layout/layout-profile.stories.d.ts.map +1 -1
  22. package/dist/components/titan-layout/layout-profile.stories.js +1 -1
  23. package/dist/components/titan-layout/layout-profile.stories.js.map +1 -1
  24. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +2 -2
  25. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
  26. package/dist/components/titan-layout/layout-sidebar-links-internal.js +4 -4
  27. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
  28. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
  29. package/dist/components/titan-layout/layout-sidebar-links.js +11 -4
  30. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
  31. package/dist/components/titan-layout/layout-sidebar.d.ts +2 -0
  32. package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
  33. package/dist/components/titan-layout/layout-sidebar.js +6 -4
  34. package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
  35. package/dist/components/titan-layout/layout-sidebar.module.less +20 -4
  36. package/dist/components/titan-layout/notifications-context.d.ts +13 -0
  37. package/dist/components/titan-layout/notifications-context.d.ts.map +1 -0
  38. package/dist/components/titan-layout/notifications-context.js +23 -0
  39. package/dist/components/titan-layout/notifications-context.js.map +1 -0
  40. package/dist/components/titan-layout/titan-layout.d.ts +5 -3
  41. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
  42. package/dist/components/titan-layout/titan-layout.js +68 -20
  43. package/dist/components/titan-layout/titan-layout.js.map +1 -1
  44. package/dist/components/titan-layout/titan-layout.module.less +43 -16
  45. package/dist/components/titan-layout/titan-layout.stories.d.ts +14 -11
  46. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
  47. package/dist/components/titan-layout/titan-layout.stories.js +33 -13
  48. package/dist/components/titan-layout/titan-layout.stories.js.map +1 -1
  49. package/dist/test/data.d.ts +4 -1
  50. package/dist/test/data.d.ts.map +1 -1
  51. package/dist/test/data.js +2 -3
  52. package/dist/test/data.js.map +1 -1
  53. package/package.json +2 -2
  54. package/src/components/badge-tag.tsx +1 -1
  55. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +1 -1
  56. package/src/components/header-navigation/header-navigation.stories.tsx +1 -1
  57. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +2 -2
  58. package/src/components/profile-dropdown/profile-dropdown.tsx +13 -6
  59. package/src/components/titan-layout/layout-header.module.less +57 -15
  60. package/src/components/titan-layout/layout-header.tsx +12 -5
  61. package/src/components/titan-layout/layout-profile.stories.tsx +10 -1
  62. package/src/components/titan-layout/layout-profile.tsx +60 -25
  63. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +18 -5
  64. package/src/components/titan-layout/layout-sidebar-links.tsx +16 -4
  65. package/src/components/titan-layout/layout-sidebar.module.less +20 -4
  66. package/src/components/titan-layout/layout-sidebar.module.less.d.ts +1 -0
  67. package/src/components/titan-layout/layout-sidebar.tsx +14 -5
  68. package/src/components/titan-layout/notifications-context.tsx +44 -0
  69. package/src/components/titan-layout/titan-layout.module.less +43 -16
  70. package/src/components/titan-layout/titan-layout.module.less.d.ts +2 -0
  71. package/src/components/titan-layout/titan-layout.stories.tsx +161 -18
  72. package/src/components/titan-layout/titan-layout.tsx +164 -60
  73. 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.SidebarLink key="tasks" {...items.tasks} />,
135
- <TitanLayout.SidebarLink key="calls" {...items.calls} />,
136
- <TitanLayout.SidebarTrigger
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 useLayoutProps = (): TitanLayoutProps => {
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
- sidebarTop: sidebarTop(),
158
- navigationComponent: NavLinkMock,
159
- extraText: 'EST (-8 hrs)',
206
+ sideTop: args.sideTop ? sidebarTop() : undefined,
207
+
208
+ minContentWidth: args.minWidth ? 900 : undefined,
160
209
  };
161
210
  };
162
211
 
163
- export const TitanLayoutLegacy = () => (
164
- <TitanLayout {...useLayoutProps()} appearance="legacy">
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
- <LocationInfo />
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
- <LocationInfo />
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
- <LocationInfo />
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
- sidebarTop?: ReactElement[];
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
- sidebarTop,
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 (!isMobile) {
144
- setMobileDrawerOpened(false);
145
- return;
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
- const [layoutStyles] = useState<object>({});
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
- ? Styles.layoutMobile
199
- : state?.navCollapsed
200
- ? Styles.layoutNavSlim
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={header}
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
- <LayoutSidebar
223
- className={Styles.side}
224
- mobile={breakpoint.isMobile}
225
- barExpanded={isMobile ? mobileDrawerOpened : !state?.navCollapsed}
226
- submenuExpanded={state?.submenuExpanded}
227
- onBarExpandChange={onBarExpandChange}
228
- onSubmenuExpandChange={onSubmenuExpandChange}
229
- top={sidebarTop}
230
- mainItems={navigationMainItems}
231
- navigationComponent={context.NavigationComponent}
232
- bottom={
233
- isMobile ? (
234
- <Fragment>
235
- {profile}
236
- {extraLinks}
237
- {!!extraText && (
238
- <InternalSideNavigationTrigger
239
- id="__extra_text"
240
- title={extraText}
241
- submenuExpanded={undefined}
242
- dataPrefix="navigation-extra-text"
243
- tag={undefined}
244
- icon={undefined}
245
- iconActive={undefined}
246
- />
247
- )}
248
- </Fragment>
249
- ) : undefined
250
- }
251
- />
252
-
253
- {content}
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
- <div className={Styles.content}>{children}</div>
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
- SidebarLink: TitanLayoutSidebarLink,
271
- SidebarTrigger: TitanLayoutSidebarTrigger,
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 }) => {