@servicetitan/navigation 11.0.0-canary.237.fef17f5.0 → 11.0.0-canary.237.ff793b3.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 (90) 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/logo/logo-titan-text.d.ts +1 -1
  10. package/dist/components/logo/logo-titan-text.d.ts.map +1 -1
  11. package/dist/components/profile-dropdown/profile-dropdown.d.ts +10 -7
  12. package/dist/components/profile-dropdown/profile-dropdown.d.ts.map +1 -1
  13. package/dist/components/profile-dropdown/profile-dropdown.js +2 -2
  14. package/dist/components/profile-dropdown/profile-dropdown.js.map +1 -1
  15. package/dist/components/profile-dropdown/profile-dropdown.module.less +2 -0
  16. package/dist/components/titan-layout/layout-context.js +1 -1
  17. package/dist/components/titan-layout/layout-context.js.map +1 -1
  18. package/dist/components/titan-layout/layout-header.d.ts +2 -0
  19. package/dist/components/titan-layout/layout-header.d.ts.map +1 -1
  20. package/dist/components/titan-layout/layout-header.js +3 -4
  21. package/dist/components/titan-layout/layout-header.js.map +1 -1
  22. package/dist/components/titan-layout/layout-header.module.less +37 -6
  23. package/dist/components/titan-layout/layout-logo.d.ts.map +1 -1
  24. package/dist/components/titan-layout/layout-logo.js +2 -1
  25. package/dist/components/titan-layout/layout-logo.js.map +1 -1
  26. package/dist/components/titan-layout/layout-profile.d.ts.map +1 -1
  27. package/dist/components/titan-layout/layout-profile.js +32 -8
  28. package/dist/components/titan-layout/layout-profile.js.map +1 -1
  29. package/dist/components/titan-layout/layout-profile.stories.d.ts.map +1 -1
  30. package/dist/components/titan-layout/layout-profile.stories.js +1 -1
  31. package/dist/components/titan-layout/layout-profile.stories.js.map +1 -1
  32. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +2 -2
  33. package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
  34. package/dist/components/titan-layout/layout-sidebar-links-internal.js +4 -4
  35. package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
  36. package/dist/components/titan-layout/layout-sidebar-links.d.ts.map +1 -1
  37. package/dist/components/titan-layout/layout-sidebar-links.js +9 -2
  38. package/dist/components/titan-layout/layout-sidebar-links.js.map +1 -1
  39. package/dist/components/titan-layout/layout-sidebar.d.ts +2 -0
  40. package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
  41. package/dist/components/titan-layout/layout-sidebar.js +6 -4
  42. package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
  43. package/dist/components/titan-layout/layout-sidebar.module.less +25 -5
  44. package/dist/components/titan-layout/notifications-context.d.ts +13 -0
  45. package/dist/components/titan-layout/notifications-context.d.ts.map +1 -0
  46. package/dist/components/titan-layout/notifications-context.js +23 -0
  47. package/dist/components/titan-layout/notifications-context.js.map +1 -0
  48. package/dist/components/titan-layout/titan-layout.d.ts +6 -3
  49. package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
  50. package/dist/components/titan-layout/titan-layout.js +77 -22
  51. package/dist/components/titan-layout/titan-layout.js.map +1 -1
  52. package/dist/components/titan-layout/titan-layout.module.less +42 -20
  53. package/dist/components/titan-layout/titan-layout.stories.d.ts +4 -0
  54. package/dist/components/titan-layout/titan-layout.stories.d.ts.map +1 -1
  55. package/dist/components/titan-layout/titan-layout.stories.js +15 -7
  56. package/dist/components/titan-layout/titan-layout.stories.js.map +1 -1
  57. package/dist/test/data.d.ts +4 -1
  58. package/dist/test/data.d.ts.map +1 -1
  59. package/dist/test/data.js +2 -3
  60. package/dist/test/data.js.map +1 -1
  61. package/dist/utils/use-breakpoint.d.ts +1 -0
  62. package/dist/utils/use-breakpoint.d.ts.map +1 -1
  63. package/dist/utils/use-breakpoint.js +2 -1
  64. package/dist/utils/use-breakpoint.js.map +1 -1
  65. package/package.json +2 -2
  66. package/src/components/badge-tag.tsx +1 -1
  67. package/src/components/header-navigation/header-navigation-stacked.stories.tsx +1 -1
  68. package/src/components/header-navigation/header-navigation.stories.tsx +1 -1
  69. package/src/components/left-navigation/header-navigation-tiny.stories.tsx +2 -2
  70. package/src/components/logo/logo-titan-text.tsx +1 -1
  71. package/src/components/profile-dropdown/profile-dropdown.module.less +2 -0
  72. package/src/components/profile-dropdown/profile-dropdown.tsx +13 -6
  73. package/src/components/titan-layout/layout-context.tsx +1 -1
  74. package/src/components/titan-layout/layout-header.module.less +37 -6
  75. package/src/components/titan-layout/layout-header.tsx +7 -4
  76. package/src/components/titan-layout/layout-logo.tsx +13 -6
  77. package/src/components/titan-layout/layout-profile.stories.tsx +10 -1
  78. package/src/components/titan-layout/layout-profile.tsx +60 -25
  79. package/src/components/titan-layout/layout-sidebar-links-internal.tsx +18 -5
  80. package/src/components/titan-layout/layout-sidebar-links.tsx +11 -2
  81. package/src/components/titan-layout/layout-sidebar.module.less +25 -5
  82. package/src/components/titan-layout/layout-sidebar.module.less.d.ts +1 -0
  83. package/src/components/titan-layout/layout-sidebar.tsx +14 -5
  84. package/src/components/titan-layout/notifications-context.tsx +44 -0
  85. package/src/components/titan-layout/titan-layout.module.less +42 -20
  86. package/src/components/titan-layout/titan-layout.module.less.d.ts +2 -1
  87. package/src/components/titan-layout/titan-layout.stories.tsx +113 -6
  88. package/src/components/titan-layout/titan-layout.tsx +218 -88
  89. package/src/test/data.tsx +2 -3
  90. package/src/utils/use-breakpoint.ts +2 -0
@@ -25,6 +25,10 @@ interface LayoutContentArgs {
25
25
  sideTop: boolean;
26
26
  extraText: boolean;
27
27
  search: boolean;
28
+ longContent: boolean;
29
+ wideContent: boolean;
30
+ minWidth: boolean;
31
+ emptyNav: boolean;
28
32
  }
29
33
 
30
34
  export default {
@@ -37,6 +41,10 @@ export default {
37
41
  sideTop: true,
38
42
  extraText: true,
39
43
  search: true,
44
+ longContent: true,
45
+ wideContent: false,
46
+ minWidth: false,
47
+ emptyNav: false,
40
48
  } as LayoutContentArgs,
41
49
  };
42
50
 
@@ -64,6 +72,7 @@ const profile = (
64
72
  to="https://google.com"
65
73
  tooltip="Google it"
66
74
  target="_blank"
75
+ tag={{ value: true }}
67
76
  >
68
77
  first link
69
78
  </ProfileDropdown.Link>
@@ -176,7 +185,9 @@ const ContentHeader = () => {
176
185
  </Fragment>
177
186
  );
178
187
  };
179
- const SearchBar = () => <TextField size="small" placeholder="Search" className="w-100-i" />;
188
+ const SearchBar = () => (
189
+ <TextField size="small" placeholder="Search" className="w-100-i m-x-half-i" />
190
+ );
180
191
 
181
192
  const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
182
193
  const [state, setState] = useState<TitanLayoutState | undefined>(undefined);
@@ -186,7 +197,7 @@ const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
186
197
  onStateChange: setState,
187
198
 
188
199
  navigationComponent: NavLinkMock,
189
- navigationMainItems: mainNavItems,
200
+ navigationMainItems: args.emptyNav ? [] : mainNavItems,
190
201
 
191
202
  profile,
192
203
  top: args.search ? <SearchBar /> : undefined,
@@ -196,15 +207,111 @@ const useLayoutProps = (args: LayoutContentArgs): TitanLayoutProps => {
196
207
  extraLinksTop,
197
208
  extraText: args.extraText ? 'EST (-8 hrs)' : undefined,
198
209
 
199
- sideTop: args.sideTop ? sidebarTop() : undefined,
210
+ sideTop: args.sideTop && !args.emptyNav ? sidebarTop() : undefined,
211
+
212
+ minContentWidth: args.minWidth ? 900 : undefined,
200
213
  };
201
214
  };
202
215
 
216
+ const Content = (args: LayoutContentArgs) => {
217
+ return (
218
+ <Fragment>
219
+ <LocationInfo className="m-b-3" />
220
+ {args.wideContent && (
221
+ <div style={{ width: '1200px' }}>
222
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
223
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
224
+ nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
225
+ Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
226
+ fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
227
+ culpa qui officia deserunt mollit anim id est laborum.
228
+ </div>
229
+ )}
230
+
231
+ {args.longContent && (
232
+ <div>
233
+ <p>Lorem</p>
234
+ <p>ipsum</p>
235
+ <p>dolor</p>
236
+ <p>sit</p>
237
+ <p>amet,</p>
238
+ <p>consectetur</p>
239
+ <p>adipiscing</p>
240
+ <p>elit,</p>
241
+ <p>sed</p>
242
+ <p>do</p>
243
+ <p>eiusmod</p>
244
+ <p>tempor</p>
245
+ <p>incididunt</p>
246
+ <p>ut</p>
247
+ <p>labore</p>
248
+ <p>et</p>
249
+ <p>dolore</p>
250
+ <p>magna</p>
251
+ <p>aliqua.</p>
252
+ <p>Ut</p>
253
+ <p>enim</p>
254
+ <p>ad</p>
255
+ <p>minim</p>
256
+ <p>veniam,</p>
257
+ <p>quis</p>
258
+ <p>nostrud</p>
259
+ <p>exercitation</p>
260
+ <p>ullamco</p>
261
+ <p>laboris</p>
262
+ <p>nisi</p>
263
+ <p>ut</p>
264
+ <p>aliquip</p>
265
+ <p>ex</p>
266
+ <p>ea</p>
267
+ <p>commodo</p>
268
+ <p>consequat.</p>
269
+ <p>Duis</p>
270
+ <p>aute</p>
271
+ <p>irure</p>
272
+ <p>dolor</p>
273
+ <p>in</p>
274
+ <p>reprehenderit</p>
275
+ <p>in</p>
276
+ <p>voluptate</p>
277
+ <p>velit</p>
278
+ <p>esse</p>
279
+ <p>cillum</p>
280
+ <p>dolore</p>
281
+ <p>eu</p>
282
+ <p>fugiat</p>
283
+ <p>nulla</p>
284
+ <p>pariatur.</p>
285
+ <p>Excepteur</p>
286
+ <p>sint</p>
287
+ <p>occaecat</p>
288
+ <p>cupidatat</p>
289
+ <p>non</p>
290
+ <p>proident,</p>
291
+ <p>sunt</p>
292
+ <p>in</p>
293
+ <p>culpa</p>
294
+ <p>qui</p>
295
+ <p>officia</p>
296
+ <p>deserunt</p>
297
+ <p>mollit</p>
298
+ <p>anim</p>
299
+ <p>id</p>
300
+ <p>est</p>
301
+ <p>laborum.</p>
302
+ </div>
303
+ )}
304
+ </Fragment>
305
+ );
306
+ };
307
+
203
308
  export const TitanLayoutLegacy = (args: LayoutContentArgs) => (
204
309
  <TitanLayout {...useLayoutProps(args)} appearance="legacy">
205
310
  <TitanLayout.Logo title />
206
311
  <TitanLayout.Content>
207
- <LocationInfo />
312
+ <div className="p-3">
313
+ <Content {...args} />
314
+ </div>
208
315
  </TitanLayout.Content>
209
316
  </TitanLayout>
210
317
  );
@@ -214,7 +321,7 @@ export const TitanLayoutAnvil1 = (args: LayoutContentArgs) => (
214
321
  <TitanLayout.Logo title />
215
322
  <TitanLayout.Content>
216
323
  <Anvil1Page>
217
- <LocationInfo />
324
+ <Content {...args} />
218
325
  </Anvil1Page>
219
326
  </TitanLayout.Content>
220
327
  </TitanLayout>
@@ -226,7 +333,7 @@ export const TitanLayoutAnvil2 = (args: LayoutContentArgs) => (
226
333
  <TitanLayout.Content>
227
334
  <Anvil2Page>
228
335
  <Anvil2Page.Content>
229
- <LocationInfo />
336
+ <Content {...args} />
230
337
  </Anvil2Page.Content>
231
338
  </Anvil2Page>
232
339
  </TitanLayout.Content>
@@ -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
- empty?: boolean;
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
 
@@ -57,6 +60,7 @@ export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
57
60
  extraLinks?: ReactElement;
58
61
  extraLinksTop?: ReactElement;
59
62
  extraText?: string;
63
+ minContentWidth?: number;
60
64
  };
61
65
 
62
66
  const defaultSidebarContext: TitanLayoutSidebarContextType = {
@@ -115,6 +119,7 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
115
119
  appearance = 'anvil2',
116
120
  id,
117
121
  children,
122
+ contentOnly,
118
123
  navigationComponent,
119
124
  header,
120
125
  top,
@@ -125,10 +130,10 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
125
130
  extraLinks,
126
131
  extraLinksTop,
127
132
  extraText,
133
+ minContentWidth,
128
134
  sideTop,
129
135
  }) => {
130
136
  const breakpoint = useTitanBreakpoint();
131
- const isMobile = breakpoint.isMobile;
132
137
  const context: TitanLayoutContextType = useMemo(
133
138
  () => ({
134
139
  NavigationComponent: navigationComponent ?? DefaultNavLinkComponent,
@@ -141,21 +146,23 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
141
146
  const variant = useVariant(appearance);
142
147
  const [mobileDrawerOpened, setMobileDrawerOpened] = useState(false);
143
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
+ }, []);
154
+
155
+ const isMobile = breakpoint.isMobile;
156
+ const hasSideBar = !contentOnly && (!!navigationMainItems?.length || !!sideTop?.length);
157
+ const hasTopBar = !contentOnly;
144
158
 
145
159
  useEffect(() => {
146
- if (!isMobile) {
147
- setMobileDrawerOpened(false);
148
- return;
160
+ if (variant.isAnvil1) {
161
+ const bodyClassName = 'of-hidden-i';
162
+ document.body.classList.add(bodyClassName);
163
+ return () => document.body.classList.remove(bodyClassName);
149
164
  }
150
-
151
- const listener = () => {
152
- setMobileDrawerOpened(false);
153
- };
154
-
155
- document.addEventListener('click', listener);
156
-
157
- return () => document.removeEventListener('click', listener);
158
- }, [isMobile]);
165
+ }, [variant.isAnvil1]);
159
166
 
160
167
  const onBurgerClick = useCallback((e: MouseEvent) => {
161
168
  setMobileDrawerOpened(true);
@@ -181,6 +188,48 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
181
188
  },
182
189
  [state, onStateChange]
183
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]);
184
233
 
185
234
  const layoutClass = variant.isLegacy
186
235
  ? Styles.layoutLegacy
@@ -196,62 +245,88 @@ const TitanLayoutComponent: FC<TitanLayoutProps> = ({
196
245
  className={classNames(
197
246
  Styles.layout,
198
247
  isMobile ? Styles.layoutMobile : Styles.layoutDesktop,
199
- !isMobile && state?.navCollapsed
200
- ? Styles.layoutNavSlim
201
- : Styles.layoutNavWide,
248
+ {
249
+ [Styles.layoutTop]: hasTopBar,
250
+ [Styles.layoutNavSlim]: !isMobile && hasSideBar && state?.navCollapsed,
251
+ [Styles.layoutNavWide]: !isMobile && hasSideBar && !state?.navCollapsed,
252
+ },
202
253
  layoutClass
203
254
  )}
255
+ style={contentStyles}
204
256
  >
205
257
  {variant.isSequent && <div className={Styles.topPlaceholder} />}
206
- <LayoutHeader
207
- className={Styles.top}
208
- logo={logo}
209
- profile={isMobile ? undefined : profile}
210
- center={top}
211
- rightText={isMobile ? undefined : extraText}
212
- right={
213
- <Fragment>
214
- {extraLinksTop}
215
- {!isMobile && extraLinks}
216
- </Fragment>
217
- }
218
- onBurgerClick={onBurgerClick}
219
- />
220
-
221
- <LayoutSidebar
222
- className={Styles.side}
223
- mobile={breakpoint.isMobile}
224
- barExpanded={isMobile ? mobileDrawerOpened : !state?.navCollapsed}
225
- submenuExpanded={state?.submenuExpanded}
226
- onBarExpandChange={onBarExpandChange}
227
- onSubmenuExpandChange={onSubmenuExpandChange}
228
- top={sideTop}
229
- mainItems={navigationMainItems}
230
- navigationComponent={context.NavigationComponent}
231
- bottom={
232
- 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={
233
266
  <Fragment>
234
- {profile}
235
- {extraLinks}
236
- {!!extraText && (
237
- <InternalSideNavigationTrigger
238
- id="__extra_text"
239
- title={extraText}
240
- submenuExpanded={undefined}
241
- dataPrefix="navigation-extra-text"
242
- tag={undefined}
243
- icon={undefined}
244
- iconActive={undefined}
245
- />
246
- )}
267
+ {extraLinksTop}
268
+ {!isMobile && extraLinks}
247
269
  </Fragment>
248
- ) : undefined
249
- }
250
- />
270
+ }
271
+ isMobile={isMobile}
272
+ hasNotifications={hasNotifications || hasMenuNotifications}
273
+ onBurgerClick={onBurgerClick}
274
+ />
275
+ )}
251
276
 
252
- <LayoutContent header={header} anvil2={variant.isAnvil2}>
253
- {content}
254
- </LayoutContent>
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
+ )}
255
330
  </div>
256
331
  </LayoutPlacementContext.Provider>
257
332
  </LayoutContext.Provider>
@@ -287,7 +362,14 @@ const TitanLayoutHeaderObserved: FC<{
287
362
  };
288
363
  }, [heightChange]);
289
364
  return (
290
- <div ref={ref} className={Styles.header}>
365
+ <div ref={ref} className={Styles.contentHeader} data-cy="layout-content-header">
366
+ {children}
367
+ </div>
368
+ );
369
+ };
370
+ const TitanLayoutHeader: FC<{ children: ReactNode }> = ({ children }) => {
371
+ return (
372
+ <div className={Styles.contentHeader} data-cy="layout-content-header">
291
373
  {children}
292
374
  </div>
293
375
  );
@@ -298,28 +380,76 @@ export interface TitanLayoutContentProps {
298
380
  }
299
381
  const TitanLayoutContent: FC<TitanLayoutContentProps> = ({ children }) => children;
300
382
 
301
- const LayoutContent: FC<{ children: ReactNode; header?: ReactNode; anvil2: boolean }> = ({
302
- anvil2,
303
- children,
304
- header,
305
- }) => {
306
- const [anvil2Styles, setAnvil2Styles] = useState<object>({});
307
- const updateIndicatorsHeight = useCallback((offset: number) => {
308
- setAnvil2Styles({ '--offset': `calc(var(--nav-offset-top) + ${offset}px)` });
309
- }, []);
310
-
383
+ const LayoutContentAnvil2: FC<{
384
+ children: ReactNode;
385
+ header?: ReactNode;
386
+ onHeaderHeightChange?: (height: number) => void;
387
+ }> = ({ children, header, onHeaderHeightChange }) => {
311
388
  return (
312
- <div className={Styles.content} style={anvil2Styles}>
313
- {!!header &&
314
- (anvil2 ? (
315
- <TitanLayoutHeaderObserved heightChange={updateIndicatorsHeight}>
316
- {header}
317
- </TitanLayoutHeaderObserved>
318
- ) : (
319
- header
320
- ))}
389
+ <Fragment>
390
+ <TitanLayoutHeaderObserved heightChange={onHeaderHeightChange}>
391
+ {header}
392
+ </TitanLayoutHeaderObserved>
321
393
  {children}
322
- </div>
394
+ </Fragment>
395
+ );
396
+ };
397
+
398
+ const LayoutContentAnvil1: FC<{
399
+ children: ReactNode;
400
+ header?: ReactNode;
401
+ minWidth?: number;
402
+ }> = ({ children, header, minWidth }) => {
403
+ const innerContentStyles: CSSProperties = useMemo(
404
+ () => ({
405
+ ...(minWidth ? { minWidth: `${minWidth}px` } : {}),
406
+ }),
407
+ [minWidth]
408
+ );
409
+
410
+ return (
411
+ <Fragment>
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>
423
+ </div>
424
+ </Fragment>
425
+ );
426
+ };
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>
323
453
  );
324
454
  };
325
455
 
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 => {
@@ -13,6 +14,7 @@ export const useTitanBreakpoint = (): TitanBreakpoint => {
13
14
  () => ({
14
15
  name: breakpoint?.name ?? 'xl',
15
16
  isMobile: breakpoint ? breakpoint.innerWidth <= 768 : false,
17
+ width: breakpoint?.innerWidth ?? 0,
16
18
  }),
17
19
  [breakpoint]
18
20
  );