@atlaskit/navigation-system 11.0.0 → 11.1.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 (83) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/entry-points/layout/chat-panel.js +12 -0
  3. package/dist/cjs/entry-points/layout/layout-sizing.js +44 -0
  4. package/dist/cjs/ui/page-layout/calculate-layout-area-states.js +179 -0
  5. package/dist/cjs/ui/page-layout/chat-panel.compiled.css +27 -0
  6. package/dist/cjs/ui/page-layout/chat-panel.js +216 -0
  7. package/dist/cjs/ui/page-layout/constants.js +6 -1
  8. package/dist/cjs/ui/page-layout/layout-area-sizing-context.js +13 -0
  9. package/dist/cjs/ui/page-layout/layout-area-sizing-provider.js +304 -0
  10. package/dist/cjs/ui/page-layout/layout-area-state-contexts.js +13 -0
  11. package/dist/cjs/ui/page-layout/main/main.js +11 -2
  12. package/dist/cjs/ui/page-layout/panel-splitter/panel-splitter.js +73 -7
  13. package/dist/cjs/ui/page-layout/panel-splitter/provider.js +7 -1
  14. package/dist/cjs/ui/page-layout/resolve-layout-width.js +13 -0
  15. package/dist/cjs/ui/page-layout/ribbon.js +1 -0
  16. package/dist/cjs/ui/page-layout/root.compiled.css +4 -2
  17. package/dist/cjs/ui/page-layout/root.js +10 -4
  18. package/dist/cjs/ui/page-layout/side-nav/side-nav.compiled.css +2 -1
  19. package/dist/cjs/ui/page-layout/side-nav/side-nav.js +152 -14
  20. package/dist/cjs/ui/page-layout/use-layout-area-sizing.js +73 -0
  21. package/dist/cjs/ui/page-layout/use-layout-main-sizing.js +15 -0
  22. package/dist/cjs/ui/page-layout/use-occupied-layout-width.js +111 -0
  23. package/dist/es2019/entry-points/layout/chat-panel.js +1 -0
  24. package/dist/es2019/entry-points/layout/layout-sizing.js +3 -0
  25. package/dist/es2019/ui/page-layout/calculate-layout-area-states.js +128 -0
  26. package/dist/es2019/ui/page-layout/chat-panel.compiled.css +27 -0
  27. package/dist/es2019/ui/page-layout/chat-panel.js +199 -0
  28. package/dist/es2019/ui/page-layout/constants.js +5 -0
  29. package/dist/es2019/ui/page-layout/layout-area-sizing-context.js +8 -0
  30. package/dist/es2019/ui/page-layout/layout-area-sizing-provider.js +279 -0
  31. package/dist/es2019/ui/page-layout/layout-area-state-contexts.js +7 -0
  32. package/dist/es2019/ui/page-layout/main/main.js +10 -2
  33. package/dist/es2019/ui/page-layout/panel-splitter/panel-splitter.js +68 -8
  34. package/dist/es2019/ui/page-layout/panel-splitter/provider.js +7 -1
  35. package/dist/es2019/ui/page-layout/resolve-layout-width.js +7 -0
  36. package/dist/es2019/ui/page-layout/ribbon.js +1 -0
  37. package/dist/es2019/ui/page-layout/root.compiled.css +4 -2
  38. package/dist/es2019/ui/page-layout/root.js +10 -4
  39. package/dist/es2019/ui/page-layout/side-nav/side-nav.compiled.css +2 -1
  40. package/dist/es2019/ui/page-layout/side-nav/side-nav.js +142 -14
  41. package/dist/es2019/ui/page-layout/use-layout-area-sizing.js +58 -0
  42. package/dist/es2019/ui/page-layout/use-layout-main-sizing.js +7 -0
  43. package/dist/es2019/ui/page-layout/use-occupied-layout-width.js +67 -0
  44. package/dist/esm/entry-points/layout/chat-panel.js +1 -0
  45. package/dist/esm/entry-points/layout/layout-sizing.js +3 -0
  46. package/dist/esm/ui/page-layout/calculate-layout-area-states.js +173 -0
  47. package/dist/esm/ui/page-layout/chat-panel.compiled.css +27 -0
  48. package/dist/esm/ui/page-layout/chat-panel.js +207 -0
  49. package/dist/esm/ui/page-layout/constants.js +5 -0
  50. package/dist/esm/ui/page-layout/layout-area-sizing-context.js +8 -0
  51. package/dist/esm/ui/page-layout/layout-area-sizing-provider.js +295 -0
  52. package/dist/esm/ui/page-layout/layout-area-state-contexts.js +7 -0
  53. package/dist/esm/ui/page-layout/main/main.js +11 -2
  54. package/dist/esm/ui/page-layout/panel-splitter/panel-splitter.js +74 -8
  55. package/dist/esm/ui/page-layout/panel-splitter/provider.js +7 -1
  56. package/dist/esm/ui/page-layout/resolve-layout-width.js +7 -0
  57. package/dist/esm/ui/page-layout/ribbon.js +1 -0
  58. package/dist/esm/ui/page-layout/root.compiled.css +4 -2
  59. package/dist/esm/ui/page-layout/root.js +10 -4
  60. package/dist/esm/ui/page-layout/side-nav/side-nav.compiled.css +2 -1
  61. package/dist/esm/ui/page-layout/side-nav/side-nav.js +153 -15
  62. package/dist/esm/ui/page-layout/use-layout-area-sizing.js +67 -0
  63. package/dist/esm/ui/page-layout/use-layout-main-sizing.js +9 -0
  64. package/dist/esm/ui/page-layout/use-occupied-layout-width.js +105 -0
  65. package/dist/types/entry-points/layout/chat-panel.d.ts +1 -0
  66. package/dist/types/entry-points/layout/layout-sizing.d.ts +4 -0
  67. package/dist/types/ui/page-layout/calculate-layout-area-states.d.ts +20 -0
  68. package/dist/types/ui/page-layout/chat-panel.d.ts +48 -0
  69. package/dist/types/ui/page-layout/constants.d.ts +4 -0
  70. package/dist/types/ui/page-layout/layout-area-sizing-context.d.ts +55 -0
  71. package/dist/types/ui/page-layout/layout-area-sizing-provider.d.ts +5 -0
  72. package/dist/types/ui/page-layout/layout-area-state-contexts.d.ts +3 -0
  73. package/dist/types/ui/page-layout/main/main.d.ts +5 -1
  74. package/dist/types/ui/page-layout/panel-splitter/panel-splitter-context.d.ts +15 -1
  75. package/dist/types/ui/page-layout/panel-splitter/provider.d.ts +1 -1
  76. package/dist/types/ui/page-layout/resolve-layout-width.d.ts +2 -0
  77. package/dist/types/ui/page-layout/side-nav/side-nav.d.ts +11 -2
  78. package/dist/types/ui/page-layout/use-layout-area-sizing.d.ts +12 -0
  79. package/dist/types/ui/page-layout/use-layout-main-sizing.d.ts +2 -0
  80. package/dist/types/ui/page-layout/use-occupied-layout-width.d.ts +8 -0
  81. package/layout/chat-panel/package.json +10 -0
  82. package/layout/layout-sizing/package.json +10 -0
  83. package/package.json +11 -3
@@ -4,7 +4,7 @@ import "./panel-splitter.compiled.css";
4
4
  import * as React from 'react';
5
5
  import { ax, ix } from "@compiled/react/runtime";
6
6
  import { forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
7
- import { createPortal } from 'react-dom';
7
+ import { createPortal, flushSync } from 'react-dom';
8
8
  import { bind } from 'bind-event-listener';
9
9
  import invariant from 'tiny-invariant';
10
10
  import { useId } from '@atlaskit/ds-lib/use-id';
@@ -135,10 +135,13 @@ const PortaledPanelSplitter = ({
135
135
  panelId,
136
136
  panelWidth,
137
137
  onCompleteResize,
138
+ onResizeStartInternal,
139
+ onResizeInternal,
138
140
  getResizeBounds,
139
141
  panel,
140
142
  portal,
141
143
  resizingCssVar,
144
+ resizingElementRef,
142
145
  position,
143
146
  tooltipContent,
144
147
  shortcut
@@ -171,9 +174,13 @@ const PortaledPanelSplitter = ({
171
174
  // Storing the initial `clientX` on `mousedown` events, to workaround a bug caused by some browser extensions
172
175
  // where the `dragstart` event incorrectly returns `0` for the `clientX` location.
173
176
  const initialClientXRef = useRef(null);
177
+ // Live allocation changes panelWidth on every frame. Only the legacy path should
178
+ // rebind the drag listeners when this value changes.
179
+ const legacyPanelWidth = fg('platform-dst-chat-panel-layout') ? undefined : panelWidth;
174
180
  useEffect(() => {
175
181
  const splitter = splitterRef.current;
176
182
  invariant(splitter, 'Splitter ref must be set');
183
+ let lastManagedResizeWidth;
177
184
  return combine(blockDraggingToIFrames({
178
185
  element: splitter
179
186
  }),
@@ -234,9 +241,16 @@ const PortaledPanelSplitter = ({
234
241
  * because some browser extensions can cause the event properties to incorrectly return 0.
235
242
  */
236
243
  invariant(isPanelSplitterDragData(source.data));
237
- onResizeStart === null || onResizeStart === void 0 ? void 0 : onResizeStart({
244
+ const resizeStartData = {
238
245
  initialWidth: source.data.initialWidth
239
- });
246
+ };
247
+ // The layout allocation system needs to know which area is actively being
248
+ // resized before the first drag update. Committing this synchronously keeps
249
+ // the actively dragged area protected from automatic compression.
250
+ if (onResizeStartInternal) {
251
+ flushSync(() => onResizeStartInternal(resizeStartData));
252
+ }
253
+ onResizeStart === null || onResizeStart === void 0 ? void 0 : onResizeStart(resizeStartData);
240
254
 
241
255
  // Close any open layers when the user starts resizing
242
256
  openLayerObserver === null || openLayerObserver === void 0 ? void 0 : openLayerObserver.closeLayers();
@@ -271,24 +285,51 @@ const PortaledPanelSplitter = ({
271
285
  position
272
286
  });
273
287
  const resizingWidth = `clamp(${resizeBounds.min}, ${targetWidth}px, ${resizeBounds.max})`;
274
- panel.style.setProperty(resizingCssVar, resizingWidth);
288
+ if (fg('platform-dst-chat-panel-layout') && onResizeInternal) {
289
+ // Let the sizing provider constrain the width against Main's available space.
290
+ const width = Math.max(convertResizeBoundToPixels(resizeBounds.min), Math.min(targetWidth, convertResizeBoundToPixels(resizeBounds.max)));
291
+ if (width !== lastManagedResizeWidth) {
292
+ lastManagedResizeWidth = width;
293
+ onResizeInternal(width);
294
+ }
295
+ } else {
296
+ var _resizingElementRef$c;
297
+ panel.style.setProperty(resizingCssVar, resizingWidth);
298
+ resizingElementRef === null || resizingElementRef === void 0 ? void 0 : (_resizingElementRef$c = resizingElementRef.current) === null || _resizingElementRef$c === void 0 ? void 0 : _resizingElementRef$c.style.setProperty(resizingCssVar, resizingWidth);
299
+ }
275
300
  source.data.resizingWidth = resizingWidth;
276
301
  },
277
302
  onDrop({
278
303
  source
279
304
  }) {
305
+ var _resizingElementRef$c2;
280
306
  invariant(isPanelSplitterDragData(source.data));
281
307
  preventUnhandled.stop();
308
+
309
+ // PDD may deliver its final throttled drag update immediately before drop.
310
+ // Commit that update once before measuring; do not persist a previous frame.
311
+ if (onResizeInternal && lastManagedResizeWidth !== undefined) {
312
+ const width = lastManagedResizeWidth;
313
+ flushSync(() => onResizeInternal(width));
314
+ lastManagedResizeWidth = undefined;
315
+ }
282
316
  const finalWidth = getPixelWidth(panel);
283
- onCompleteResize(finalWidth);
317
+ // Persist the final preferred width before removing the imperative drag
318
+ // variable, so the rendered width is continuous across pointer release.
319
+ if (fg('platform-dst-chat-panel-layout')) {
320
+ flushSync(() => onCompleteResize(finalWidth));
321
+ } else {
322
+ onCompleteResize(finalWidth);
323
+ }
284
324
  onResizeEnd === null || onResizeEnd === void 0 ? void 0 : onResizeEnd({
285
325
  initialWidth: source.data.initialWidth,
286
326
  finalWidth
287
327
  });
288
328
  panel.style.removeProperty(resizingCssVar);
329
+ resizingElementRef === null || resizingElementRef === void 0 ? void 0 : (_resizingElementRef$c2 = resizingElementRef.current) === null || _resizingElementRef$c2 === void 0 ? void 0 : _resizingElementRef$c2.style.removeProperty(resizingCssVar);
289
330
  }
290
331
  }));
291
- }, [onCompleteResize, onResizeStart, onResizeEnd, panel, resizingCssVar, panelWidth, position, openLayerObserver, panelId, getResizeBounds]);
332
+ }, [onCompleteResize, onResizeStartInternal, onResizeInternal, onResizeStart, onResizeEnd, panel, resizingCssVar, resizingElementRef, legacyPanelWidth, position, openLayerObserver, panelId, getResizeBounds]);
292
333
  const onResizeStartStableRef = useStableRef(onResizeStart);
293
334
  const onResizeEndStableRef = useStableRef(onResizeEnd);
294
335
  const [keyboardResizeManager] = useState(() => createKeyboardResizeManager({
@@ -304,7 +345,20 @@ const PortaledPanelSplitter = ({
304
345
  }
305
346
  }));
306
347
  const handleSliderInputChange = useCallback(event => {
307
- const value = parseInt(event.target.value);
348
+ const isManagedResize = fg('platform-dst-chat-panel-layout') && onResizeInternal;
349
+ let value = isManagedResize ? parseFloat(event.target.value) : parseInt(event.target.value);
350
+ if (isManagedResize) {
351
+ // The available region may have changed since focus, including without a
352
+ // window resize. Use the allocator's current bounds for the public payload.
353
+ const bounds = getResizeBounds();
354
+ const min = convertResizeBoundToPixels(bounds.min);
355
+ const max = convertResizeBoundToPixels(bounds.max);
356
+ value = Math.max(min, Math.min(value, max));
357
+ setRangeInputBounds({
358
+ min,
359
+ max
360
+ });
361
+ }
308
362
  setRangeInputValue(value);
309
363
 
310
364
  /**
@@ -316,7 +370,7 @@ const PortaledPanelSplitter = ({
316
370
  initialWidth: panelWidth,
317
371
  finalWidth: value
318
372
  });
319
- }, [onCompleteResize, panelWidth, keyboardResizeManager]);
373
+ }, [getResizeBounds, onCompleteResize, onResizeInternal, panelWidth, keyboardResizeManager]);
320
374
  const resizeEventListenerCleanupFn = useRef(null);
321
375
  const handleSliderFocus = useCallback(() => {
322
376
  var _resizeEventListenerC;
@@ -435,8 +489,11 @@ export const PanelSplitter = ({
435
489
  panelId,
436
490
  panelWidth,
437
491
  onCompleteResize,
492
+ onResizeStartInternal,
493
+ onResizeInternal,
438
494
  getResizeBounds,
439
495
  resizingCssVar,
496
+ resizingElementRef,
440
497
  position,
441
498
  shortcut
442
499
  } = context;
@@ -532,8 +589,11 @@ export const PanelSplitter = ({
532
589
  portal: portal,
533
590
  panelWidth: panelWidth,
534
591
  onCompleteResize: onCompleteResize,
592
+ onResizeStartInternal: onResizeStartInternal,
593
+ onResizeInternal: onResizeInternal,
535
594
  getResizeBounds: getResizeBounds,
536
595
  resizingCssVar: resizingCssVar,
596
+ resizingElementRef: resizingElementRef,
537
597
  position: position,
538
598
  tooltipContent: tooltipContent,
539
599
  shortcut: shortcut
@@ -9,9 +9,12 @@ export const PanelSplitterProvider = ({
9
9
  panelId,
10
10
  panelWidth,
11
11
  onCompleteResize,
12
+ onResizeStartInternal,
13
+ onResizeInternal,
12
14
  getResizeBounds,
13
15
  resizingCssVar,
14
16
  panelRef,
17
+ resizingElementRef,
15
18
  portalRef: providedPortalRef,
16
19
  position = 'end',
17
20
  isEnabled = true,
@@ -23,14 +26,17 @@ export const PanelSplitterProvider = ({
23
26
  panelId,
24
27
  panelWidth,
25
28
  onCompleteResize,
29
+ onResizeStartInternal,
30
+ onResizeInternal,
26
31
  getResizeBounds,
27
32
  resizingCssVar,
28
33
  position,
29
34
  panelRef,
35
+ resizingElementRef,
30
36
  isEnabled,
31
37
  portalRef: typeof providedPortalRef !== 'undefined' ? providedPortalRef : portalRef,
32
38
  shortcut
33
- }), [panelId, panelWidth, onCompleteResize, getResizeBounds, resizingCssVar, position, panelRef, isEnabled, providedPortalRef, shortcut]);
39
+ }), [panelId, panelWidth, onCompleteResize, onResizeStartInternal, onResizeInternal, getResizeBounds, resizingCssVar, position, panelRef, resizingElementRef, isEnabled, providedPortalRef, shortcut]);
34
40
  return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(PanelSplitterContext.Provider, {
35
41
  value: context
36
42
  }, children), typeof providedPortalRef !== 'undefined' ? null : /*#__PURE__*/React.createElement("div", {
@@ -0,0 +1,7 @@
1
+ export function resolveLayoutWidth(bound, viewportWidth) {
2
+ if (typeof bound === 'number') {
3
+ return bound;
4
+ }
5
+ const value = Number.parseFloat(bound);
6
+ return bound.endsWith('vw') ? viewportWidth * value / 100 : value;
7
+ }
@@ -8,6 +8,7 @@ import { DangerouslyHoistCssVarToDocumentRoot } from './dangerously-hoist-css-va
8
8
  import { DangerouslyHoistSlotSizes } from './hoist-slot-sizes-context';
9
9
  import { useLayoutId } from './use-layout-id';
10
10
  const localSlotLayersStatic = {
11
+ chatPanelOverlay: 5,
11
12
  ribbon: 4,
12
13
  // The side nav panel splitter is layered above the top nav when FHS is enabled.
13
14
  // It has the same z-index value, but is rendered after the top nav in the DOM so is stacked above.
@@ -1,5 +1,6 @@
1
1
  ._18m9zryt{overflow-y:clip}
2
2
  ._1ciragmp >:not([data-layout-slot]){display:none!important}
3
+ ._1cwmtye8{--n_mainMinW:20rem}
3
4
  ._1e0c11p5{display:grid}
4
5
  ._1lmcq9em{grid-template-areas:"banner" "top-bar" "main" "aside"}
5
6
  ._1reozryt{overflow-x:clip}
@@ -7,5 +8,6 @@
7
8
  ._1tvnagmp >:not([data-layout-slot]):not(dialog):not([popover]){display:none!important}
8
9
  ._2z0516ab{grid-template-rows:auto auto 1fr auto}
9
10
  ._yv0ei47z{grid-template-columns:minmax(0,1fr)}
10
- @media (min-width:64rem){._12fk1aio{grid-template-areas:"banner banner banner banner" "ribbon top-bar top-bar top-bar" "ribbon side-nav main aside"}._12qzrxre{grid-template-rows:auto auto 3fr}._1rqteala{grid-template-columns:auto auto minmax(0,1fr) auto}}
11
- @media (min-width:90rem){._xkmgks3h{grid-template-areas:"banner banner banner banner banner" "ribbon top-bar top-bar top-bar top-bar" "ribbon side-nav main aside panel"}._jbc7rxre{grid-template-rows:auto auto 3fr}._tyve1nco{grid-template-columns:auto auto minmax(0,1fr) auto auto}}
11
+ @media (min-width:40rem){._12ag50j2{grid-template-areas:"banner banner" "top-bar chat-panel" "main chat-panel" "aside chat-panel"}._71dlqwpl{grid-template-columns:minmax(var(--n_mainMinW),1fr) minmax(0,max-content)}}
12
+ @media (min-width:64rem){._12fk1aio{grid-template-areas:"banner banner banner banner" "ribbon top-bar top-bar top-bar" "ribbon side-nav main aside"}._12qzrxre{grid-template-rows:auto auto 3fr}._1rqteala{grid-template-columns:auto auto minmax(0,1fr) auto}._12fkqmyk{grid-template-areas:"banner banner banner banner banner" "ribbon top-bar top-bar top-bar chat-panel" "ribbon side-nav main aside chat-panel"}._1rqt8mqp{grid-template-columns:auto auto minmax(var(--n_mainMinW),1fr) auto minmax(0,max-content)}}
13
+ @media (min-width:90rem){._xkmggc7l{grid-template-areas:"banner banner banner banner banner banner" "ribbon top-bar top-bar top-bar top-bar chat-panel" "ribbon side-nav main aside panel chat-panel"}._tyve1i18{grid-template-columns:auto auto minmax(var(--n_mainMinW),1fr) auto auto minmax(0,max-content)}._xkmgks3h{grid-template-areas:"banner banner banner banner banner" "ribbon top-bar top-bar top-bar top-bar" "ribbon side-nav main aside panel"}._jbc7rxre{grid-template-rows:auto auto 3fr}._tyve1nco{grid-template-columns:auto auto minmax(0,1fr) auto auto}}
@@ -7,6 +7,7 @@ import { fg } from '@atlaskit/platform-feature-flags/fg';
7
7
  import { SkipLinksProvider } from '../../context/skip-links/skip-links-provider';
8
8
  import { TopNavStartProvider } from '../../context/top-nav-start/top-nav-start-context-provider';
9
9
  import { DangerouslyHoistSlotSizes } from './hoist-slot-sizes-context';
10
+ import { LayoutAreaSizingProvider } from './layout-area-sizing-provider';
10
11
  import { IsSideNavShortcutEnabledProvider } from './side-nav/is-side-nav-shortcut-enabled-provider';
11
12
  import { SideNavElementProvider } from './side-nav/side-nav-element-provider';
12
13
  import { SideNavToggleButtonProvider } from './side-nav/toggle-button-provider';
@@ -15,7 +16,8 @@ import { SideNavVisibilityProvider } from './side-nav/visibility-provider';
15
16
  // ID of the root element that the banner and top bar slots hoist their sizes to. Only internally exported.
16
17
  export const gridRootId = 'unsafe-design-system-page-layout-root';
17
18
  const styles = {
18
- root: "_1e0c11p5 _1tke1kxc _1lmcq9em _yv0ei47z _2z0516ab _12fk1aio _12qzrxre _1rqteala _xkmgks3h _jbc7rxre _tyve1nco",
19
+ legacyRoot: "_1e0c11p5 _1tke1kxc _1lmcq9em _yv0ei47z _2z0516ab _12fk1aio _12qzrxre _1rqteala _xkmgks3h _jbc7rxre _tyve1nco",
20
+ root: "_1cwmtye8 _1e0c11p5 _1tke1kxc _1lmcq9em _yv0ei47z _2z0516ab _12ag50j2 _71dlqwpl _12fkqmyk _12qzrxre _1rqt8mqp _xkmggc7l _tyve1i18",
19
21
  safetyRail: "_1ciragmp",
20
22
  safetyRailWithTopLayer: "_1tvnagmp",
21
23
  panelUplift: "_1reozryt _18m9zryt"
@@ -36,6 +38,8 @@ export function Root({
36
38
  isSideNavShortcutEnabled = false
37
39
  }) {
38
40
  const ref = useRef(null);
41
+ const isChatPanelLayoutEnabled = fg('platform-dst-chat-panel-layout');
42
+ const LayoutProvider = isChatPanelLayoutEnabled ? LayoutAreaSizingProvider : React.Fragment;
39
43
  useEffect(() => {
40
44
  if (process.env.NODE_ENV !== 'production') {
41
45
  const IGNORED_ELEMENTS = ['SCRIPT', 'STYLE'];
@@ -65,7 +69,9 @@ This message will not be displayed in production.
65
69
  defaultCollapsed: defaultSideNavCollapsed
66
70
  }, /*#__PURE__*/React.createElement(SideNavToggleButtonProvider, null, /*#__PURE__*/React.createElement(SideNavElementProvider, null, /*#__PURE__*/React.createElement(IsSideNavShortcutEnabledProvider, {
67
71
  isSideNavShortcutEnabled: isSideNavShortcutEnabled
68
- }, /*#__PURE__*/React.createElement(TopNavStartProvider, null, /*#__PURE__*/React.createElement(OpenLayerObserver, null, /*#__PURE__*/React.createElement(DangerouslyHoistSlotSizes.Provider, {
72
+ }, /*#__PURE__*/React.createElement(TopNavStartProvider, null, /*#__PURE__*/React.createElement(LayoutProvider, isChatPanelLayoutEnabled ? {
73
+ layoutRef: ref
74
+ } : {}, /*#__PURE__*/React.createElement(OpenLayerObserver, null, /*#__PURE__*/React.createElement(DangerouslyHoistSlotSizes.Provider, {
69
75
  value: UNSAFE_dangerouslyHoistSlotSizes
70
76
  }, /*#__PURE__*/React.createElement(SkipLinksProvider, {
71
77
  label: skipLinksLabel,
@@ -73,8 +79,8 @@ This message will not be displayed in production.
73
79
  testId: testId
74
80
  }, /*#__PURE__*/React.createElement("div", {
75
81
  ref: ref,
76
- className: ax([styles.root, fg('platform-dst-motion-uplift-panel') && styles.panelUplift, fg('platform-dst-top-layer') ? styles.safetyRailWithTopLayer : styles.safetyRail, xcss]),
82
+ className: ax([isChatPanelLayoutEnabled ? styles.root : styles.legacyRoot, fg('platform-dst-motion-uplift-panel') && styles.panelUplift, fg('platform-dst-top-layer') ? styles.safetyRailWithTopLayer : styles.safetyRail, xcss]),
77
83
  id: gridRootId,
78
84
  "data-testid": testId
79
- }, children)))))))));
85
+ }, children))))))))));
80
86
  }
@@ -4,6 +4,7 @@
4
4
  ._16qs130s{box-shadow:var(--ds-shadow-overlay,0 8px 9pt #1e1f2126,0 0 1px #1e1f214f)}
5
5
  ._1bah1yb4{justify-content:space-between}
6
6
  ._1bsb1ego{width:min(90%,20pc)}
7
+ ._1bsbhc79{width:var(--n_snvRsz,var(--n_sNvw))}
7
8
  ._1e0c1txw{display:flex}
8
9
  ._1e0cglyw{display:none}
9
10
  ._1p2s1vfh{--exit-animation:var(--ds-sidenav-exit-left,200ms cubic-bezier(0,0.4,0,1) SlideOut100PercentLeft)}
@@ -24,7 +25,7 @@
24
25
  [dir=rtl] ._65m41mrw{--animation-direction:-1}
25
26
  @media (prefers-reduced-motion:no-preference){._10t81t0s{transition-property:display}._1vrh1a5r{transition-behavior:allow-discrete}._xrrpi9qs{transition-duration:var(--ds-duration-medium,.2s)}._10t88iot{transition-property:transform,display}._xrrpfnf5{transition-duration:.2s}._1lh81gzg{grid-area:main}._1xq51mm8{transition-timing-function:cubic-bezier(0,.4,0,1)}._k1affm5y{animation:var(--exit-animation)}@starting-style{._1nu51p9u{transform:translateX(calc(-100%*var(--animation-direction)))}}._1xq51ku9{transition-timing-function:cubic-bezier(.6,0,0,1)}._k1af10ed{animation:var(--enter-animation)}}
26
27
  @media (min-width:48rem){._14b5hc79{width:var(--n_snvRsz,var(--n_sNvw))}}
27
- @media (min-width:64rem){._165t56xv{height:calc(100vh - var(--n_bnrM, 0px))}._p0az1elq{transform:translateX(calc(var(--n_snvRsz, var(--n_snvW, 0px)) - var(--ds-border-width, 1px)))}._dm2518uv{display:initial}._dm25glyw{display:none}._qiln1gzg{grid-area:main}._p5clglyw{border-inline-end:none}._4ap31bhr{background-color:var(--ds-surface-overlay,#fff)}._scbp130s{box-shadow:var(--ds-shadow-overlay,0 8px 9pt #1e1f2126,0 0 1px #1e1f214f)}._qilnk0mc{grid-area:side-nav}._p5clia51{border-inline-end:var(--ds-border-width,1px) solid var(--ds-border,#0b120e24)}._4ap3vuon{background-color:var(--ds-surface,#fff)}._scbpglyw{box-shadow:none}}
28
+ @media (min-width:64rem){._165t56xv{height:calc(100vh - var(--n_bnrM, 0px))}._p0az1elq{transform:translateX(calc(var(--n_snvRsz, var(--n_snvW, 0px)) - var(--ds-border-width, 1px)))}._cpcf1gzg._cpcf1gzg{grid-area:main}._6kttglyw._6kttglyw{border-inline-end:none}._w8v11bhr._w8v11bhr{background-color:var(--ds-surface-overlay,#fff)}._1jug130s._1jug130s{box-shadow:var(--ds-shadow-overlay,0 8px 9pt #1e1f2126,0 0 1px #1e1f214f)}._dm2518uv{display:initial}._dm25glyw{display:none}._qiln1gzg{grid-area:main}._p5clglyw{border-inline-end:none}._4ap31bhr{background-color:var(--ds-surface-overlay,#fff)}._scbp130s{box-shadow:var(--ds-shadow-overlay,0 8px 9pt #1e1f2126,0 0 1px #1e1f214f)}._qilnk0mc{grid-area:side-nav}._p5clia51{border-inline-end:var(--ds-border-width,1px) solid var(--ds-border,#0b120e24)}._4ap3vuon{background-color:var(--ds-surface,#fff)}._scbpglyw{box-shadow:none}}
28
29
  @media (prefers-reduced-motion:no-preference) and (min-width:64rem){._17ly8iot{transition-property:transform,display}._177m1a5r{transition-behavior:allow-discrete}._1sg81gzg{grid-area:main}._n2infm5y{animation:var(--exit-animation)}._17ly1wzp{transition-property:grid-area,display}._hjoi1wsm{transition-duration:var(--ds-duration-instant,0ms),var(--ds-duration-medium,.2s)}._1wxo1cio{transition-delay:19ms,var(--ds-duration-instant,0ms)}._vgub1mm8{transition-timing-function:cubic-bezier(0,.4,0,1)}._hh1u1p9u{transform:translateX(calc(-100%*var(--animation-direction)))}@starting-style{._1xpz1gzg{grid-area:main}}._1sg8k0mc{grid-area:side-nav}._n2in10ed{animation:var(--enter-animation)}._17ly1q8v{transition-property:grid-area}._hjoi147i{transition-duration:var(--ds-duration-instant,0ms)}._1wxo4so3{transition-delay:24ms}@starting-style{._s2eg1p9u{transform:translateX(calc(-100%*var(--animation-direction)))}}._vgub1ku9{transition-timing-function:cubic-bezier(.6,0,0,1)}._hjoifnf5{transition-duration:.2s}._hjoi1mzy{transition-duration:var(--ds-duration-long,.25s)}._hjoii9qs{transition-duration:var(--ds-duration-medium,.2s)}}
29
30
  @media (prefers-reduced-motion:no-preference) and (not (min-width:64rem)){._aadi1p9u{transform:translateX(calc(-100%*var(--animation-direction)))}}
30
31
  @media not (min-width:64rem){._89fi1b6c{grid-area:main/aside/aside/aside}}
@@ -17,10 +17,13 @@ import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/el
17
17
  import { useSkipLinkInternal } from '../../../context/skip-links/use-skip-link-internal';
18
18
  import { TopNavStartElement } from '../../../context/top-nav-start/top-nav-start-element';
19
19
  import { useIsFhsEnabled } from '../../fhs-rollout/use-is-fhs-enabled';
20
- import { UNSAFE_sideNavLayoutVar, openLayerObserverSideNavNamespace, openLayerObserverTopNavStartNamespace, sideNavLiveWidthVar, sideNavPanelSplitterId, sideNavVar } from '../constants';
20
+ import { UNSAFE_sideNavLayoutVar, mainMinimumWidthVar, openLayerObserverSideNavNamespace, openLayerObserverTopNavStartNamespace, sideNavLiveWidthVar, sideNavPanelSplitterId, sideNavVar } from '../constants';
21
21
  import { DangerouslyHoistCssVarToDocumentRoot } from '../dangerously-hoist-css-var-to-document-root';
22
22
  import { DangerouslyHoistSlotSizes } from '../hoist-slot-sizes-context';
23
+ import { convertResizeBoundToPixels } from '../panel-splitter/convert-resize-bound-to-pixels';
23
24
  import { PanelSplitterProvider } from '../panel-splitter/provider';
25
+ import { resolveLayoutWidth } from '../resolve-layout-width';
26
+ import { useLayoutAreaSizing } from '../use-layout-area-sizing';
24
27
  import { useLayoutId } from '../use-layout-id';
25
28
  import { useResizingWidthCssVarOnRootElement } from '../use-resizing-width-css-var-on-root-element';
26
29
  import { useSafeDefaultWidth } from '../use-safe-default-width';
@@ -40,12 +43,11 @@ const panelSplitterResizingVar = '--n_snvRsz';
40
43
  // Used to share the side nav width with the panel splitter, which is rendered outside the side nav element
41
44
  // but positioned to stay at its right edge.
42
45
  const sideNavClampedWidthVar = '--n_snvW';
43
- const widthResizeBounds = {
44
- min: '240px',
45
- max: '50vw'
46
- };
47
- function getResizeBounds() {
48
- return widthResizeBounds;
46
+ const fallbackMinWidth = '240px';
47
+ function getPixelCustomProperty(element, propertyName, fallback) {
48
+ const raw = getComputedStyle(element).getPropertyValue(propertyName).trim();
49
+ const value = Number.parseFloat(raw);
50
+ return Number.isFinite(value) ? resolveLayoutWidth(raw.endsWith('vw') ? `${value}vw` : value, window.innerWidth) : fallback;
49
51
  }
50
52
 
51
53
  /**
@@ -59,6 +61,8 @@ const panelSplitterPortalTargetStyles = {
59
61
  };
60
62
  const styles = {
61
63
  root: "_191wglyw _t51zglyw _bfhk1bhr _16qs130s _vchhusvi _4t3ieqxy _152timx3 _kqsw1if8 _1bsb1ego _1pbycs5v _14b5hc79 _qilnk0mc _p5clia51 _4ap3vuon _scbpglyw _89fi1b6c",
64
+ chatPanelSizing: "_1bsbhc79",
65
+ managedOverlay: "_cpcf1gzg _6kttglyw _w8v11bhr _1jug130s",
62
66
  flyoutOpen: "_qiln1gzg _p5clglyw _4ap31bhr _scbp130s _139f8iot _1tpvfnf5 _sylc1a5r _oyeijq3t",
63
67
  flyoutAnimateClosed: "_1e0cglyw _qiln1gzg _139f8iot _1tpvfnf5 _sylc1a5r _1uwsjq3t",
64
68
  animationRTLSupport: "_15yekb7n _65m41mrw",
@@ -111,6 +115,8 @@ function SideNavInternal({
111
115
  children,
112
116
  defaultCollapsed,
113
117
  defaultWidth: defaultWidthProp = fallbackDefaultWidth,
118
+ minWidth = fallbackMinWidth,
119
+ maxWidth,
114
120
  testId,
115
121
  label = 'Sidebar',
116
122
  skipLinkLabel = label,
@@ -121,7 +127,8 @@ function SideNavInternal({
121
127
  id: providedId,
122
128
  canToggleWithShortcut
123
129
  }) {
124
- var _sideNavState$lastTri;
130
+ var _managedSizing$mode, _managedSizing$width, _sideNavState$lastTri;
131
+ const isChatPanelLayoutEnabled = fg('platform-dst-chat-panel-layout');
125
132
  const isFhsEnabled = useIsFhsEnabled();
126
133
  const id = useLayoutId({
127
134
  providedId
@@ -203,17 +210,132 @@ function SideNavInternal({
203
210
  fallbackDefaultWidth,
204
211
  slotName: 'SideNav'
205
212
  });
206
- const [width, setWidth] = useState(defaultWidth);
207
- const clampedWidth = `clamp(${widthResizeBounds.min}, ${width}px, ${widthResizeBounds.max})`;
213
+ const [inlineWidth, setInlineWidth] = useState(defaultWidth);
214
+ const [overlayWidth, setOverlayWidth] = useState(defaultWidth);
215
+ const [isInline, setIsInline] = useState(false);
216
+ useEffect(() => {
217
+ if (!isChatPanelLayoutEnabled) {
218
+ return;
219
+ }
220
+ const mediaQuery = window.matchMedia('(min-width: 64rem)');
221
+ setIsInline(mediaQuery.matches);
222
+ const onChange = event => setIsInline(event.matches);
223
+ return bind(mediaQuery, {
224
+ type: 'change',
225
+ listener: onChange
226
+ });
227
+ }, [isChatPanelLayoutEnabled]);
228
+ const toggleVisibilityForChatPanel = useToggleSideNav({
229
+ trigger: 'programmatic'
230
+ });
231
+ const closeOverlayForChatPanel = useCallback(() => {
232
+ // Allocation can overlay an expanded desktop nav when other slots consume
233
+ // its space. Dismiss the visibility state selected by the viewport, not the mode.
234
+ const isDesktop = window.matchMedia('(min-width: 64rem)').matches;
235
+ if (isDesktop ? isExpandedOnDesktop : isExpandedOnMobile) {
236
+ toggleVisibilityForChatPanel();
237
+ }
238
+ }, [isExpandedOnDesktop, isExpandedOnMobile, toggleVisibilityForChatPanel]);
239
+ const {
240
+ state: managedSizing,
241
+ getResizeBounds: getManagedResizeBounds,
242
+ startResize,
243
+ resize,
244
+ completeResize
245
+ } = useLayoutAreaSizing({
246
+ area: 'side-nav',
247
+ config: {
248
+ defaultWidth,
249
+ minWidth,
250
+ maxWidth,
251
+ isOpen: isInline ? isExpandedOnDesktop : isExpandedOnMobile,
252
+ onRequestClose: closeOverlayForChatPanel
253
+ }
254
+ });
255
+ const mode = (_managedSizing$mode = managedSizing === null || managedSizing === void 0 ? void 0 : managedSizing.mode) !== null && _managedSizing$mode !== void 0 ? _managedSizing$mode : isInline ? 'inline' : 'overlay';
256
+ const renderedWidth = isChatPanelLayoutEnabled ? (_managedSizing$width = managedSizing === null || managedSizing === void 0 ? void 0 : managedSizing.width) !== null && _managedSizing$width !== void 0 ? _managedSizing$width : mode === 'inline' ? inlineWidth : overlayWidth : inlineWidth;
257
+ const configuredMaxWidth = maxWidth !== null && maxWidth !== void 0 ? maxWidth : '100vw';
258
+ const clampedWidth = !isChatPanelLayoutEnabled ? `clamp(240px, ${inlineWidth}px, 50vw)` : managedSizing ? `${renderedWidth}px` : `clamp(${minWidth}, ${renderedWidth}px, ${configuredMaxWidth})`;
208
259
  const dangerouslyHoistSlotSizes = useContext(DangerouslyHoistSlotSizes);
209
260
  const navRef = useRef(null);
210
261
  const panelSplitterPortalTargetRef = useRef(null);
262
+ const getResizeBounds = useCallback(() => {
263
+ if (!isChatPanelLayoutEnabled) {
264
+ return {
265
+ min: '240px',
266
+ max: '50vw'
267
+ };
268
+ }
269
+ const managedBounds = getManagedResizeBounds();
270
+ if (managedBounds) {
271
+ return managedBounds;
272
+ }
273
+ const sideNav = navRef.current;
274
+ const layoutRoot = sideNav === null || sideNav === void 0 ? void 0 : sideNav.parentElement;
275
+ const main = layoutRoot === null || layoutRoot === void 0 ? void 0 : layoutRoot.querySelector(':scope > [data-layout-slot][role="main"]');
276
+ const fallbackMaxWidth = maxWidth !== null && maxWidth !== void 0 ? maxWidth : mode === 'inline' ? '100vw' : '90vw';
277
+ if (!sideNav || mode === 'overlay') {
278
+ const chatPanel = layoutRoot === null || layoutRoot === void 0 ? void 0 : layoutRoot.querySelector(':scope > [data-layout-chat-panel]');
279
+ const inlineChatPanelWidth = chatPanel && getComputedStyle(chatPanel).gridArea === 'chat-panel' ? chatPanel.getBoundingClientRect().width : 0;
280
+ const overlayMaxWidth = Math.floor((window.innerWidth - inlineChatPanelWidth) * 0.9);
281
+ const constrainedMaxWidth = maxWidth ? Math.min(convertResizeBoundToPixels(maxWidth), overlayMaxWidth) : overlayMaxWidth;
282
+ return {
283
+ min: minWidth,
284
+ max: `${Math.max(convertResizeBoundToPixels(minWidth), constrainedMaxWidth)}px`
285
+ };
286
+ }
287
+ if (!main) {
288
+ return {
289
+ min: minWidth,
290
+ max: fallbackMaxWidth
291
+ };
292
+ }
293
+ const sideNavWidth = sideNav.getBoundingClientRect().width;
294
+ const mainWidth = main.getBoundingClientRect().width;
295
+
296
+ // JSDOM does not perform layout, so retain the static fallback in unit tests and other
297
+ // environments where used widths cannot be measured.
298
+ if (sideNavWidth === 0 || mainWidth === 0) {
299
+ return {
300
+ min: minWidth,
301
+ max: fallbackMaxWidth
302
+ };
303
+ }
304
+ const localPanel = main.querySelector('[data-layout-with-panel-slot]');
305
+ const isLocalPanelInline = localPanel && getComputedStyle(localPanel).gridArea === 'panel';
306
+ const localPanelWidth = isLocalPanelInline ? localPanel.getBoundingClientRect().width : 0;
307
+ const mainContentWidth = mainWidth - localPanelWidth;
308
+ const mainMinimumWidth = getPixelCustomProperty(main, mainMinimumWidthVar, 320);
309
+ const availableWidth = Math.max(0, mainContentWidth - mainMinimumWidth);
310
+ const availableInlineWidth = Math.floor(sideNavWidth + availableWidth);
311
+ const constrainedMaxWidth = maxWidth ? Math.min(convertResizeBoundToPixels(maxWidth), availableInlineWidth) : availableInlineWidth;
312
+ return {
313
+ min: minWidth,
314
+ max: `${Math.max(convertResizeBoundToPixels(minWidth), constrainedMaxWidth)}px`
315
+ };
316
+ }, [getManagedResizeBounds, isChatPanelLayoutEnabled, maxWidth, minWidth, mode]);
211
317
  /**
212
318
  * Used to share the side nav element with the `Panel`,
213
319
  * which observes the side nav to determine its maximum width.
214
320
  */
215
321
  const sharedRef = useSideNavRef();
216
322
  const mergedRef = mergeRefs([navRef, sharedRef]);
323
+ const onCompleteResize = useCallback(finalWidth => {
324
+ if (!isChatPanelLayoutEnabled) {
325
+ setInlineWidth(finalWidth);
326
+ return;
327
+ }
328
+ if (mode === 'inline') {
329
+ setInlineWidth(finalWidth);
330
+ } else {
331
+ setOverlayWidth(finalWidth);
332
+ }
333
+ completeResize(mode, finalWidth);
334
+ }, [completeResize, isChatPanelLayoutEnabled, mode]);
335
+ const onResizeStartInternal = useCallback(() => {
336
+ startResize(mode);
337
+ }, [mode, startResize]);
338
+ const onResizeInternal = useCallback(width => resize(mode, width), [mode, resize]);
217
339
  const toggleButtonElement = useContext(SideNavToggleButtonElement);
218
340
  const topNavStartElement = useContext(TopNavStartElement);
219
341
  const devTimeOnlyAttributes = {};
@@ -713,7 +835,7 @@ function SideNavInternal({
713
835
  // Used to conditionally display the keyboard shortcut in the SideNavPanelSplitter tooltip.
714
836
  const isShortcutEnabled = useIsSideNavShortcutEnabled();
715
837
  useResizingWidthCssVarOnRootElement({
716
- isEnabled: true,
838
+ isEnabled: !isChatPanelLayoutEnabled || !managedSizing,
717
839
  cssVar: panelSplitterResizingVar,
718
840
  panelId: sideNavPanelSplitterId
719
841
  });
@@ -778,7 +900,7 @@ function SideNavInternal({
778
900
  },
779
901
  ref: mergedRef,
780
902
  "data-testid": testId,
781
- className: ax([styles.root, isExpandedOnDesktop && !isExpandedOnMobile && !isFlyoutVisible && styles.hiddenMobileOnly, !isExpandedOnDesktop && isExpandedOnMobile && !isFlyoutVisible && styles.hiddenDesktopOnly, !isExpandedOnDesktop && !isExpandedOnMobile && !isFlyoutVisible && styles.hiddenMobileAndDesktop, isMotionUpliftEnabled && motionUpliftStyles.animationRTLSupport, !isMotionUpliftEnabled && isFhsEnabled && styles.animationRTLSupport, shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.animationBaseStyles, shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.animationBaseStyles, isExpandedOnMobile && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.expandAnimationMobile, isExpandedOnMobile && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.expandAnimationMobile, !isExpandedOnMobile && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.collapseAnimationMobile, !isExpandedOnMobile && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.collapseAnimationMobile, isExpandedOnDesktop && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.expandAnimationDesktop, isExpandedOnDesktop && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.expandAnimationDesktop, !isExpandedOnDesktop && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.collapseAnimationDesktop, !isExpandedOnDesktop && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.collapseAnimationDesktop, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutOpen, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutOpen, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutAnimateClosed, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutAnimateClosed, ((sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' || (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close') && !isFirefox && isFhsEnabled && styles.flyoutBaseStylesFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFirefox && isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutOpenFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFirefox && isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutOpenFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFirefox && isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutAnimateClosedFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFirefox && isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutAnimateClosedFullHeightSidebar])
903
+ className: ax([styles.root, isChatPanelLayoutEnabled && styles.chatPanelSizing, isChatPanelLayoutEnabled && (managedSizing === null || managedSizing === void 0 ? void 0 : managedSizing.mode) === 'overlay' && styles.managedOverlay, isExpandedOnDesktop && !isExpandedOnMobile && !isFlyoutVisible && styles.hiddenMobileOnly, !isExpandedOnDesktop && isExpandedOnMobile && !isFlyoutVisible && styles.hiddenDesktopOnly, !isExpandedOnDesktop && !isExpandedOnMobile && !isFlyoutVisible && styles.hiddenMobileAndDesktop, isMotionUpliftEnabled && motionUpliftStyles.animationRTLSupport, !isMotionUpliftEnabled && isFhsEnabled && styles.animationRTLSupport, shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.animationBaseStyles, shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.animationBaseStyles, isExpandedOnMobile && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.expandAnimationMobile, isExpandedOnMobile && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.expandAnimationMobile, !isExpandedOnMobile && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.collapseAnimationMobile, !isExpandedOnMobile && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.collapseAnimationMobile, isExpandedOnDesktop && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.expandAnimationDesktop, isExpandedOnDesktop && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.expandAnimationDesktop, !isExpandedOnDesktop && shouldShowSidebarToggleAnimation && isMotionUpliftEnabled && motionUpliftStyles.collapseAnimationDesktop, !isExpandedOnDesktop && shouldShowSidebarToggleAnimation && !isMotionUpliftEnabled && styles.collapseAnimationDesktop, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutOpen, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutOpen, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutAnimateClosed, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutAnimateClosed, ((sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' || (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close') && !isFirefox && isFhsEnabled && styles.flyoutBaseStylesFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFirefox && isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutOpenFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open' && !isFirefox && isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutOpenFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFirefox && isFhsEnabled && isMotionUpliftEnabled && motionUpliftStyles.flyoutAnimateClosedFullHeightSidebar, (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'triggered-animate-close' && !isFirefox && isFhsEnabled && !isMotionUpliftEnabled && styles.flyoutAnimateClosedFullHeightSidebar])
782
904
  }), /*#__PURE__*/React.createElement(DangerouslyHoistCssVarToDocumentRoot, {
783
905
  variableName: sideNavLiveWidthVar,
784
906
  value: "0px",
@@ -798,8 +920,10 @@ function SideNavInternal({
798
920
  panelId: sideNavPanelSplitterId,
799
921
  panelRef: navRef,
800
922
  portalRef: isFhsEnabled ? panelSplitterPortalTargetRef : undefined,
801
- panelWidth: width,
802
- onCompleteResize: setWidth,
923
+ panelWidth: renderedWidth,
924
+ onCompleteResize: onCompleteResize,
925
+ onResizeStartInternal: isChatPanelLayoutEnabled && managedSizing ? onResizeStartInternal : undefined,
926
+ onResizeInternal: isChatPanelLayoutEnabled && managedSizing ? onResizeInternal : undefined,
803
927
  getResizeBounds: getResizeBounds,
804
928
  resizingCssVar: panelSplitterResizingVar
805
929
  // Not resizable when in peek (flyout) mode.
@@ -834,6 +958,8 @@ export function SideNav({
834
958
  children,
835
959
  defaultCollapsed,
836
960
  defaultWidth = 320,
961
+ minWidth,
962
+ maxWidth,
837
963
  testId,
838
964
  label,
839
965
  // Default value is defined in `SideNavInternal`
@@ -851,6 +977,8 @@ export function SideNav({
851
977
  }, /*#__PURE__*/React.createElement(SideNavInternal, {
852
978
  defaultCollapsed: defaultCollapsed,
853
979
  defaultWidth: defaultWidth,
980
+ minWidth: minWidth,
981
+ maxWidth: maxWidth,
854
982
  testId: testId,
855
983
  label: label,
856
984
  skipLinkLabel: skipLinkLabel,
@@ -0,0 +1,58 @@
1
+ import { useCallback, useContext, useEffect, useRef } from 'react';
2
+ import { LayoutAreaSizingContext } from './layout-area-sizing-context';
3
+ import { layoutAreaStateContexts } from './layout-area-state-contexts';
4
+ export function useLayoutAreaSizing({
5
+ area,
6
+ config
7
+ }) {
8
+ const context = useContext(LayoutAreaSizingContext);
9
+ const {
10
+ requestedWidth,
11
+ defaultWidth,
12
+ compactDefaultWidth,
13
+ minWidth,
14
+ maxWidth,
15
+ isOpen,
16
+ onRequestClose
17
+ } = config;
18
+ const registerArea = context === null || context === void 0 ? void 0 : context.registerArea;
19
+ const unregisterArea = context === null || context === void 0 ? void 0 : context.unregisterArea;
20
+ const startAreaResize = context === null || context === void 0 ? void 0 : context.startResize;
21
+ const resizeArea = context === null || context === void 0 ? void 0 : context.resize;
22
+ const completeAreaResize = context === null || context === void 0 ? void 0 : context.completeResize;
23
+ const getAreaResizeBounds = context === null || context === void 0 ? void 0 : context.getResizeBounds;
24
+ const state = useContext(layoutAreaStateContexts[area]);
25
+ // Dismissal is not a sizing input. Register a stable delegate while keeping
26
+ // the consumer's latest committed callback outside allocation state.
27
+ const onRequestCloseRef = useRef(onRequestClose);
28
+ useEffect(() => {
29
+ onRequestCloseRef.current = onRequestClose;
30
+ }, [onRequestClose]);
31
+ const requestClose = useCallback(() => {
32
+ var _onRequestCloseRef$cu;
33
+ return (_onRequestCloseRef$cu = onRequestCloseRef.current) === null || _onRequestCloseRef$cu === void 0 ? void 0 : _onRequestCloseRef$cu.call(onRequestCloseRef);
34
+ }, []);
35
+ useEffect(() => {
36
+ registerArea === null || registerArea === void 0 ? void 0 : registerArea(area, {
37
+ requestedWidth,
38
+ defaultWidth,
39
+ compactDefaultWidth,
40
+ minWidth,
41
+ maxWidth,
42
+ isOpen,
43
+ onRequestClose: requestClose
44
+ });
45
+ }, [area, compactDefaultWidth, defaultWidth, isOpen, maxWidth, minWidth, registerArea, requestClose, requestedWidth]);
46
+ useEffect(() => () => unregisterArea === null || unregisterArea === void 0 ? void 0 : unregisterArea(area), [area, unregisterArea]);
47
+ const startResize = useCallback(mode => startAreaResize === null || startAreaResize === void 0 ? void 0 : startAreaResize(area, mode), [area, startAreaResize]);
48
+ const resize = useCallback((mode, width) => resizeArea === null || resizeArea === void 0 ? void 0 : resizeArea(area, mode, width), [area, resizeArea]);
49
+ const completeResize = useCallback((mode, width) => completeAreaResize === null || completeAreaResize === void 0 ? void 0 : completeAreaResize(area, mode, width), [area, completeAreaResize]);
50
+ const getResizeBounds = useCallback(() => getAreaResizeBounds === null || getAreaResizeBounds === void 0 ? void 0 : getAreaResizeBounds(area), [area, getAreaResizeBounds]);
51
+ return {
52
+ state,
53
+ startResize,
54
+ resize,
55
+ completeResize,
56
+ getResizeBounds
57
+ };
58
+ }
@@ -0,0 +1,7 @@
1
+ import { useContext, useEffect } from 'react';
2
+ import { LayoutAreaSizingContext } from './layout-area-sizing-context';
3
+ export function useLayoutMainSizing(minWidth) {
4
+ const context = useContext(LayoutAreaSizingContext);
5
+ const setMainMinWidth = context === null || context === void 0 ? void 0 : context.setMainMinWidth;
6
+ useEffect(() => setMainMinWidth === null || setMainMinWidth === void 0 ? void 0 : setMainMinWidth(minWidth), [minWidth, setMainMinWidth]);
7
+ }