@atlaskit/navigation-system 11.3.3 → 11.4.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 (97) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +20 -0
  3. package/constellation/layout/code.mdx +1 -1
  4. package/constellation/layout/examples.mdx +4 -16
  5. package/constellation/layout/images/layout-anatomy-dark.png +0 -0
  6. package/constellation/layout/images/layout-anatomy-light.png +0 -0
  7. package/constellation/layout/images/layout-do-dark.png +0 -0
  8. package/constellation/layout/images/layout-do-light.png +0 -0
  9. package/constellation/layout/images/layout-dont-dark.png +0 -0
  10. package/constellation/layout/images/layout-dont-light.png +0 -0
  11. package/constellation/layout/images/layout-example-dark.png +0 -0
  12. package/constellation/layout/images/layout-example-light.png +0 -0
  13. package/constellation/layout/images/layout-example-sideNav-dark.png +0 -0
  14. package/constellation/layout/images/layout-example-sideNav-light.png +0 -0
  15. package/constellation/layout/images/layout-example-topNav-1-dark.png +0 -0
  16. package/constellation/layout/images/layout-example-topNav-1-light.png +0 -0
  17. package/constellation/layout/usage.mdx +1 -2
  18. package/constellation/top-nav-items/examples.mdx +7 -13
  19. package/dist/cjs/entry-points/layout/panel-layout.js +19 -0
  20. package/dist/cjs/ui/page-layout/calculate-layout-area-states.js +4 -4
  21. package/dist/cjs/ui/page-layout/chat-panel.js +1 -1
  22. package/dist/cjs/ui/page-layout/constants.js +15 -1
  23. package/dist/cjs/ui/page-layout/get-panel-layout-defaults.js +22 -0
  24. package/dist/cjs/ui/page-layout/layout-area-sizing-provider.js +2 -1
  25. package/dist/cjs/ui/page-layout/layout-area-sizing-runtime.js +5 -4
  26. package/dist/cjs/ui/page-layout/local-panel-surface.compiled.css +26 -0
  27. package/dist/cjs/ui/page-layout/local-panel-surface.js +206 -0
  28. package/dist/cjs/ui/page-layout/main/main.js +5 -2
  29. package/dist/cjs/ui/page-layout/main-min-width-context.js +10 -0
  30. package/dist/cjs/ui/page-layout/panel-layout-shell.compiled.css +27 -0
  31. package/dist/cjs/ui/page-layout/panel-layout-shell.js +67 -0
  32. package/dist/cjs/ui/page-layout/panel-layout.js +162 -0
  33. package/dist/cjs/ui/page-layout/panel-splitter/panel-splitter.js +12 -5
  34. package/dist/cjs/ui/page-layout/root.js +3 -1
  35. package/dist/cjs/ui/page-layout/side-nav/bind-open-layer-change.js +56 -0
  36. package/dist/cjs/ui/page-layout/side-nav/side-nav.js +167 -57
  37. package/dist/cjs/ui/page-layout/side-nav/toggle-button.js +8 -1
  38. package/dist/cjs/ui/page-layout/side-nav/use-side-nav-toggle-keyboard-shortcut.js +15 -1
  39. package/dist/cjs/ui/page-layout/top-nav/top-nav-end.js +3 -2
  40. package/dist/cjs/ui/page-layout/top-nav/top-nav-middle.js +2 -1
  41. package/dist/es2019/entry-points/layout/panel-layout.js +2 -0
  42. package/dist/es2019/ui/page-layout/calculate-layout-area-states.js +4 -4
  43. package/dist/es2019/ui/page-layout/chat-panel.js +2 -2
  44. package/dist/es2019/ui/page-layout/constants.js +14 -0
  45. package/dist/es2019/ui/page-layout/get-panel-layout-defaults.js +16 -0
  46. package/dist/es2019/ui/page-layout/layout-area-sizing-provider.js +2 -1
  47. package/dist/es2019/ui/page-layout/layout-area-sizing-runtime.js +4 -3
  48. package/dist/es2019/ui/page-layout/local-panel-surface.compiled.css +26 -0
  49. package/dist/es2019/ui/page-layout/local-panel-surface.js +193 -0
  50. package/dist/es2019/ui/page-layout/main/main.js +6 -3
  51. package/dist/es2019/ui/page-layout/main-min-width-context.js +5 -0
  52. package/dist/es2019/ui/page-layout/panel-layout-shell.compiled.css +27 -0
  53. package/dist/es2019/ui/page-layout/panel-layout-shell.js +74 -0
  54. package/dist/es2019/ui/page-layout/panel-layout.js +147 -0
  55. package/dist/es2019/ui/page-layout/panel-splitter/panel-splitter.js +12 -5
  56. package/dist/es2019/ui/page-layout/root.js +3 -1
  57. package/dist/es2019/ui/page-layout/side-nav/bind-open-layer-change.js +51 -0
  58. package/dist/es2019/ui/page-layout/side-nav/side-nav.js +123 -10
  59. package/dist/es2019/ui/page-layout/side-nav/toggle-button.js +8 -1
  60. package/dist/es2019/ui/page-layout/side-nav/use-side-nav-toggle-keyboard-shortcut.js +15 -1
  61. package/dist/es2019/ui/page-layout/top-nav/top-nav-end.js +3 -2
  62. package/dist/es2019/ui/page-layout/top-nav/top-nav-middle.js +2 -1
  63. package/dist/esm/entry-points/layout/panel-layout.js +2 -0
  64. package/dist/esm/ui/page-layout/calculate-layout-area-states.js +4 -4
  65. package/dist/esm/ui/page-layout/chat-panel.js +2 -2
  66. package/dist/esm/ui/page-layout/constants.js +14 -0
  67. package/dist/esm/ui/page-layout/get-panel-layout-defaults.js +16 -0
  68. package/dist/esm/ui/page-layout/layout-area-sizing-provider.js +2 -1
  69. package/dist/esm/ui/page-layout/layout-area-sizing-runtime.js +4 -3
  70. package/dist/esm/ui/page-layout/local-panel-surface.compiled.css +26 -0
  71. package/dist/esm/ui/page-layout/local-panel-surface.js +197 -0
  72. package/dist/esm/ui/page-layout/main/main.js +6 -3
  73. package/dist/esm/ui/page-layout/main-min-width-context.js +5 -0
  74. package/dist/esm/ui/page-layout/panel-layout-shell.compiled.css +27 -0
  75. package/dist/esm/ui/page-layout/panel-layout-shell.js +59 -0
  76. package/dist/esm/ui/page-layout/panel-layout.js +154 -0
  77. package/dist/esm/ui/page-layout/panel-splitter/panel-splitter.js +12 -5
  78. package/dist/esm/ui/page-layout/root.js +3 -1
  79. package/dist/esm/ui/page-layout/side-nav/bind-open-layer-change.js +50 -0
  80. package/dist/esm/ui/page-layout/side-nav/side-nav.js +168 -58
  81. package/dist/esm/ui/page-layout/side-nav/toggle-button.js +8 -1
  82. package/dist/esm/ui/page-layout/side-nav/use-side-nav-toggle-keyboard-shortcut.js +15 -1
  83. package/dist/esm/ui/page-layout/top-nav/top-nav-end.js +3 -2
  84. package/dist/esm/ui/page-layout/top-nav/top-nav-middle.js +2 -1
  85. package/dist/types/entry-points/layout/panel-layout.d.ts +3 -0
  86. package/dist/types/ui/page-layout/constants.d.ts +12 -0
  87. package/dist/types/ui/page-layout/get-panel-layout-defaults.d.ts +10 -0
  88. package/dist/types/ui/page-layout/layout-area-sizing-context.d.ts +5 -1
  89. package/dist/types/ui/page-layout/local-panel-surface.d.ts +32 -0
  90. package/dist/types/ui/page-layout/main-min-width-context.d.ts +2 -0
  91. package/dist/types/ui/page-layout/panel-layout-shell.d.ts +47 -0
  92. package/dist/types/ui/page-layout/panel-layout.d.ts +74 -0
  93. package/dist/types/ui/page-layout/side-nav/bind-open-layer-change.d.ts +17 -0
  94. package/layout/panel-layout/package.json +10 -0
  95. package/package.json +6 -6
  96. package/constellation/layout/images/layout-example-topNav-2-dark.png +0 -0
  97. package/constellation/layout/images/layout-example-topNav-2-light.png +0 -0
@@ -18,9 +18,10 @@ import { fg } from '@atlaskit/platform-feature-flags/fg';
18
18
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/adapter/element-adapter';
19
19
  // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- TODO: migrate to @atlaskit/primitives/compiled
20
20
 
21
+ import { hasOpenDialogOrPopover } from '@atlaskit/top-layer/page-surface/has-open-dialog-or-popover';
21
22
  import { useSkipLinkInternal } from '../../../context/skip-links/use-skip-link-internal';
22
23
  import { TopNavStartElement } from '../../../context/top-nav-start/top-nav-start-element';
23
- import { UNSAFE_sideNavLayoutVar, mainMinimumWidthVar, openLayerObserverSideNavNamespace, sideNavLiveWidthVar, sideNavPanelSplitterId, sideNavVar } from '../constants';
24
+ import { UNSAFE_sideNavLayoutVar, defaultMainMinWidth, mainMinimumWidthVar, openLayerObserverSideNavNamespace, sideNavLiveWidthVar, sideNavPanelSplitterId, sideNavVar } from '../constants';
24
25
  import { DangerouslyHoistCssVarToDocumentRoot } from '../dangerously-hoist-css-var-to-document-root';
25
26
  import { DangerouslyHoistSlotSizes } from '../hoist-slot-sizes-context';
26
27
  import { convertResizeBoundToPixels } from '../panel-splitter/convert-resize-bound-to-pixels';
@@ -31,6 +32,7 @@ import { useLayoutAreaSizing } from '../use-layout-area-sizing';
31
32
  import { useLayoutId } from '../use-layout-id';
32
33
  import { useResizingWidthCssVarOnRootElement } from '../use-resizing-width-css-var-on-root-element';
33
34
  import { useSafeDefaultWidth } from '../use-safe-default-width';
35
+ import { bindOpenLayerChange } from './bind-open-layer-change';
34
36
  import { sideNavFlyoutCloseDelayMs } from './flyout-close-delay-ms';
35
37
  import { SetSideNavVisibilityState } from './set-side-nav-visibility-state';
36
38
  import { SideNavToggleButtonElement } from './side-nav-toggle-button-element';
@@ -57,6 +59,51 @@ function getPixelCustomProperty(element, propertyName, fallback) {
57
59
  * Avoiding nesting the `@supports` at-rule inside of `@media` means Compiled can remove duplicate styles from the generated CSS.
58
60
  */
59
61
  var isFirefox = typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
62
+ var textEntryInputTypes = new Set(['text', 'search', 'email', 'url', 'tel', 'password', 'number']);
63
+ function isEditableContent(_ref) {
64
+ var element = _ref.element;
65
+ if (element instanceof HTMLElement && typeof element.isContentEditable === 'boolean') {
66
+ return element.isContentEditable;
67
+ }
68
+ // Fallback for DOM implementations without `isContentEditable`.
69
+ var editingHost = element.closest('[contenteditable]');
70
+ return editingHost !== null && editingHost.getAttribute('contenteditable') !== 'false';
71
+ }
72
+
73
+ /**
74
+ * Returns `true` for an element that the user can type text into.
75
+ */
76
+ function isTextEntryElement(_ref2) {
77
+ var element = _ref2.element;
78
+ if (element instanceof HTMLInputElement) {
79
+ return textEntryInputTypes.has(element.type) && !element.readOnly && !element.disabled;
80
+ }
81
+ if (element instanceof HTMLTextAreaElement) {
82
+ return !element.readOnly && !element.disabled;
83
+ }
84
+ return isEditableContent({
85
+ element: element
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Used when the `platform-dst-top-layer` gate is on.
91
+ *
92
+ * The flyout stays open while a layer opened from the side nav is open, or while the user
93
+ * is typing in a text field inside the side nav (for example while renaming an item inline).
94
+ */
95
+ function isFlyoutHeldOpen(_ref3) {
96
+ var nav = _ref3.nav;
97
+ if (hasOpenDialogOrPopover({
98
+ within: nav
99
+ })) {
100
+ return true;
101
+ }
102
+ var activeElement = nav.ownerDocument.activeElement;
103
+ return activeElement !== null && nav.contains(activeElement) && isTextEntryElement({
104
+ element: activeElement
105
+ });
106
+ }
60
107
  var styles = {
61
108
  root: "_191wglyw _t51zglyw _bfhk1bhr _16qs130s _vchhusvi _4t3ieqxy _152timx3 _kqsw1if8 _1bsb1ego _1pbycs5v _14b5hc79 _qilnk0mc _p5clia51 _4ap3vuon _scbpglyw _89fi1b6c",
62
109
  chatPanelSizing: "_1bsbhc79",
@@ -98,26 +145,26 @@ export var onPeekStartDelayMs = 500;
98
145
  * We need an additional component layer so we can wrap the side nav in a `OpenLayerObserver` and have access to the
99
146
  * context value.
100
147
  */
101
- function SideNavInternal(_ref) {
148
+ function SideNavInternal(_ref4) {
102
149
  var _managedSizing$mode, _managedSizing$width, _sideNavState$lastTri;
103
- var children = _ref.children,
104
- defaultCollapsed = _ref.defaultCollapsed,
105
- _ref$defaultWidth = _ref.defaultWidth,
106
- defaultWidthProp = _ref$defaultWidth === void 0 ? fallbackDefaultWidth : _ref$defaultWidth,
107
- _ref$minWidth = _ref.minWidth,
108
- minWidth = _ref$minWidth === void 0 ? fallbackMinWidth : _ref$minWidth,
109
- maxWidth = _ref.maxWidth,
110
- testId = _ref.testId,
111
- _ref$label = _ref.label,
112
- label = _ref$label === void 0 ? 'Sidebar' : _ref$label,
113
- _ref$skipLinkLabel = _ref.skipLinkLabel,
114
- skipLinkLabel = _ref$skipLinkLabel === void 0 ? label : _ref$skipLinkLabel,
115
- onExpand = _ref.onExpand,
116
- onCollapse = _ref.onCollapse,
117
- onPeekStart = _ref.onPeekStart,
118
- onPeekEnd = _ref.onPeekEnd,
119
- providedId = _ref.id,
120
- canToggleWithShortcut = _ref.canToggleWithShortcut;
150
+ var children = _ref4.children,
151
+ defaultCollapsed = _ref4.defaultCollapsed,
152
+ _ref4$defaultWidth = _ref4.defaultWidth,
153
+ defaultWidthProp = _ref4$defaultWidth === void 0 ? fallbackDefaultWidth : _ref4$defaultWidth,
154
+ _ref4$minWidth = _ref4.minWidth,
155
+ minWidth = _ref4$minWidth === void 0 ? fallbackMinWidth : _ref4$minWidth,
156
+ maxWidth = _ref4.maxWidth,
157
+ testId = _ref4.testId,
158
+ _ref4$label = _ref4.label,
159
+ label = _ref4$label === void 0 ? 'Sidebar' : _ref4$label,
160
+ _ref4$skipLinkLabel = _ref4.skipLinkLabel,
161
+ skipLinkLabel = _ref4$skipLinkLabel === void 0 ? label : _ref4$skipLinkLabel,
162
+ onExpand = _ref4.onExpand,
163
+ onCollapse = _ref4.onCollapse,
164
+ onPeekStart = _ref4.onPeekStart,
165
+ onPeekEnd = _ref4.onPeekEnd,
166
+ providedId = _ref4.id,
167
+ canToggleWithShortcut = _ref4.canToggleWithShortcut;
121
168
  var isChatPanelLayoutEnabled = fg('platform-dst-chat-panel-layout');
122
169
  var id = useLayoutId({
123
170
  providedId: providedId
@@ -307,7 +354,7 @@ function SideNavInternal(_ref) {
307
354
  var isLocalPanelInline = localPanel && getComputedStyle(localPanel).gridArea === 'panel';
308
355
  var localPanelWidth = isLocalPanelInline ? localPanel.getBoundingClientRect().width : 0;
309
356
  var mainContentWidth = mainWidth - localPanelWidth;
310
- var mainMinimumWidth = getPixelCustomProperty(main, mainMinimumWidthVar, 320);
357
+ var mainMinimumWidth = getPixelCustomProperty(main, mainMinimumWidthVar, defaultMainMinWidth);
311
358
  var availableWidth = Math.max(0, mainContentWidth - mainMinimumWidth);
312
359
  var availableInlineWidth = Math.floor(sideNavWidth + availableWidth);
313
360
  var constrainedMaxWidth = maxWidth ? Math.min(convertResizeBoundToPixels(maxWidth), availableInlineWidth) : availableInlineWidth;
@@ -343,7 +390,9 @@ function SideNavInternal(_ref) {
343
390
  var toggleButtonElement = useContext(SideNavToggleButtonElement);
344
391
  var topNavStartElement = useContext(TopNavStartElement);
345
392
  var devTimeOnlyAttributes = {};
346
- var openLayerObserver = useOpenLayerObserver();
393
+ var openLayerObserver = useOpenLayerObserver({
394
+ isEnabled: !fg('platform-dst-top-layer')
395
+ });
347
396
  var flyoutStateRef = useRef({
348
397
  type: 'not-active'
349
398
  });
@@ -421,6 +470,17 @@ function SideNavInternal(_ref) {
421
470
  });
422
471
  }
423
472
  }
473
+ function canClose() {
474
+ if (!fg('platform-dst-top-layer')) {
475
+ return (openLayerObserver === null || openLayerObserver === void 0 ? void 0 : openLayerObserver.getCount({
476
+ namespace: openLayerObserverSideNavNamespace
477
+ })) === 0;
478
+ }
479
+ var nav = navRef.current;
480
+ return !(nav && isFlyoutHeldOpen({
481
+ nav: nav
482
+ }));
483
+ }
424
484
  return function onAction(action) {
425
485
  if (action === 'drag-from-flyout-started') {
426
486
  open();
@@ -462,9 +522,7 @@ function SideNavInternal(_ref) {
462
522
  }
463
523
  if (action === 'ready-to-close') {
464
524
  // If there are no open layers, we can close the flyout.
465
- if ((openLayerObserver === null || openLayerObserver === void 0 ? void 0 : openLayerObserver.getCount({
466
- namespace: openLayerObserverSideNavNamespace
467
- })) === 0) {
525
+ if (canClose()) {
468
526
  close();
469
527
  return;
470
528
  }
@@ -505,9 +563,9 @@ function SideNavInternal(_ref) {
505
563
  });
506
564
  });
507
565
  }, [initialDefaultCollapsed, setSideNavState, sideNavState]);
508
- var handleExpand = useCallback(function (_ref2) {
509
- var screen = _ref2.screen,
510
- trigger = _ref2.trigger;
566
+ var handleExpand = useCallback(function (_ref5) {
567
+ var screen = _ref5.screen,
568
+ trigger = _ref5.trigger;
511
569
  onExpand === null || onExpand === void 0 || onExpand({
512
570
  screen: screen,
513
571
  trigger: trigger
@@ -527,9 +585,9 @@ function SideNavInternal(_ref) {
527
585
  // This prevents the flyout from staying open and ensures we are respecting the user's intent to expand.
528
586
  updateFlyoutState('force-close');
529
587
  }, [onExpand, updateFlyoutState, createAnalyticsEvent]);
530
- var handleCollapse = useCallback(function (_ref3) {
531
- var screen = _ref3.screen,
532
- trigger = _ref3.trigger;
588
+ var handleCollapse = useCallback(function (_ref6) {
589
+ var screen = _ref6.screen,
590
+ trigger = _ref6.trigger;
533
591
  onCollapse === null || onCollapse === void 0 || onCollapse({
534
592
  screen: screen,
535
593
  trigger: trigger
@@ -722,15 +780,15 @@ function SideNavInternal(_ref) {
722
780
  // we are just interested in listening to events within an element
723
781
  // - We do not want to impact `location.{*}.dropTargets` in events
724
782
  return monitorForElements({
725
- canMonitor: function canMonitor(_ref4) {
726
- var source = _ref4.source;
783
+ canMonitor: function canMonitor(_ref7) {
784
+ var source = _ref7.source;
727
785
  return nav.contains(source.element);
728
786
  },
729
787
  onGenerateDragPreview: function onGenerateDragPreview() {
730
788
  updateFlyoutState('drag-from-flyout-started');
731
789
  },
732
- onDrop: function onDrop(_ref5) {
733
- var location = _ref5.location;
790
+ onDrop: function onDrop(_ref8) {
791
+ var location = _ref8.location;
734
792
  // Always marking the drag and done
735
793
  updateFlyoutState('drag-from-flyout-finished');
736
794
 
@@ -791,8 +849,8 @@ function SideNavInternal(_ref) {
791
849
  // Close the flyout if there are no more layers open and the user is not mousing over the
792
850
  // flyout areas (side nav, TopNavStart element)
793
851
 
794
- return openLayerObserver === null || openLayerObserver === void 0 ? void 0 : openLayerObserver.onChange(function (_ref6) {
795
- var count = _ref6.count;
852
+ return openLayerObserver === null || openLayerObserver === void 0 ? void 0 : openLayerObserver.onChange(function (_ref9) {
853
+ var count = _ref9.count;
796
854
  if (flyoutStateRef.current.type === 'ready-to-close' && count === 0) {
797
855
  updateFlyoutState('force-close');
798
856
  }
@@ -800,6 +858,52 @@ function SideNavInternal(_ref) {
800
858
  namespace: openLayerObserverSideNavNamespace
801
859
  });
802
860
  }, [openLayerObserver, updateFlyoutState]);
861
+ var focusOutTimeoutIdRef = useRef(undefined);
862
+ useEffect(function () {
863
+ // The same as the open layer observer `onChange` above, for when the `platform-dst-top-layer`
864
+ // gate is on. Top-layer surfaces opened from the side nav are DOM descendants of it.
865
+ var nav = navRef.current;
866
+ if (!nav || !fg('platform-dst-top-layer')) {
867
+ return;
868
+ }
869
+ function closeIfReady() {
870
+ if (flyoutStateRef.current.type !== 'ready-to-close' || !nav) {
871
+ return;
872
+ }
873
+ if (isFlyoutHeldOpen({
874
+ nav: nav
875
+ })) {
876
+ return;
877
+ }
878
+ updateFlyoutState('force-close');
879
+ }
880
+ var unbindLayerChange = bindOpenLayerChange({
881
+ within: nav,
882
+ onChange: closeIfReady
883
+ });
884
+ var unbindFocusOut = bind(nav, {
885
+ type: 'focusout',
886
+ listener: function listener() {
887
+ // Wait for focus to move before checking where it went.
888
+ clearTimeout(focusOutTimeoutIdRef.current);
889
+ focusOutTimeoutIdRef.current = setTimeout(closeIfReady, 0);
890
+ }
891
+ });
892
+
893
+ // Removing the focused text field (for example when an inline rename ends) fires no
894
+ // `focusout` in some browsers, so also check again when content inside the side nav changes.
895
+ var removalObserver = new MutationObserver(closeIfReady);
896
+ removalObserver.observe(nav, {
897
+ childList: true,
898
+ subtree: true
899
+ });
900
+ return function cleanup() {
901
+ unbindLayerChange();
902
+ unbindFocusOut();
903
+ removalObserver.disconnect();
904
+ clearTimeout(focusOutTimeoutIdRef.current);
905
+ };
906
+ }, [updateFlyoutState]);
803
907
  useEffect(function () {
804
908
  // Clear flyout close timer if being unmounted
805
909
  return function cleanupPendingFlyoutClose() {
@@ -936,26 +1040,24 @@ function SideNavInternal(_ref) {
936
1040
  *
937
1041
  * You can optionally render a `PanelSplitter` as a child to make the side navigation slot resizable.
938
1042
  */
939
- export function SideNav(_ref8) {
940
- var children = _ref8.children,
941
- defaultCollapsed = _ref8.defaultCollapsed,
942
- _ref8$defaultWidth = _ref8.defaultWidth,
943
- defaultWidth = _ref8$defaultWidth === void 0 ? 320 : _ref8$defaultWidth,
944
- minWidth = _ref8.minWidth,
945
- maxWidth = _ref8.maxWidth,
946
- testId = _ref8.testId,
947
- label = _ref8.label,
948
- _ref8$skipLinkLabel = _ref8.skipLinkLabel,
949
- skipLinkLabel = _ref8$skipLinkLabel === void 0 ? label : _ref8$skipLinkLabel,
950
- onExpand = _ref8.onExpand,
951
- onCollapse = _ref8.onCollapse,
952
- onPeekStart = _ref8.onPeekStart,
953
- onPeekEnd = _ref8.onPeekEnd,
954
- canToggleWithShortcut = _ref8.canToggleWithShortcut,
955
- id = _ref8.id;
956
- return /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
957
- namespace: openLayerObserverSideNavNamespace
958
- }, /*#__PURE__*/React.createElement(SideNavInternal, {
1043
+ export function SideNav(_ref1) {
1044
+ var children = _ref1.children,
1045
+ defaultCollapsed = _ref1.defaultCollapsed,
1046
+ _ref1$defaultWidth = _ref1.defaultWidth,
1047
+ defaultWidth = _ref1$defaultWidth === void 0 ? 320 : _ref1$defaultWidth,
1048
+ minWidth = _ref1.minWidth,
1049
+ maxWidth = _ref1.maxWidth,
1050
+ testId = _ref1.testId,
1051
+ label = _ref1.label,
1052
+ _ref1$skipLinkLabel = _ref1.skipLinkLabel,
1053
+ skipLinkLabel = _ref1$skipLinkLabel === void 0 ? label : _ref1$skipLinkLabel,
1054
+ onExpand = _ref1.onExpand,
1055
+ onCollapse = _ref1.onCollapse,
1056
+ onPeekStart = _ref1.onPeekStart,
1057
+ onPeekEnd = _ref1.onPeekEnd,
1058
+ canToggleWithShortcut = _ref1.canToggleWithShortcut,
1059
+ id = _ref1.id;
1060
+ var sideNav = /*#__PURE__*/React.createElement(SideNavInternal, {
959
1061
  defaultCollapsed: defaultCollapsed,
960
1062
  defaultWidth: defaultWidth,
961
1063
  minWidth: minWidth,
@@ -969,5 +1071,13 @@ export function SideNav(_ref8) {
969
1071
  onPeekEnd: onPeekEnd,
970
1072
  id: id,
971
1073
  canToggleWithShortcut: canToggleWithShortcut
972
- }, children));
1074
+ }, children);
1075
+
1076
+ // Top-layer surfaces are found through the DOM, so the namespace is only needed when the gate is off.
1077
+ if (fg('platform-dst-top-layer')) {
1078
+ return sideNav;
1079
+ }
1080
+ return /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
1081
+ namespace: openLayerObserverSideNavNamespace
1082
+ }, sideNav);
973
1083
  }
@@ -11,6 +11,8 @@ import { useAnalyticsEvents } from '@atlaskit/analytics-next/useAnalyticsEvents'
11
11
  import SidebarCollapseIcon from '@atlaskit/icon/core/sidebar-collapse';
12
12
  import SidebarExpandIcon from '@atlaskit/icon/core/sidebar-expand';
13
13
  import { useOpenLayerObserver } from '@atlaskit/layering/use-open-layer-observer';
14
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
15
+ import { requestClosePopovers } from '@atlaskit/top-layer/page-surface/request-close-popovers';
14
16
  import { IconButton } from '../../top-nav-items/themed/icon-button';
15
17
  import { SideNavToggleButtonAttachRef } from './side-nav-toggle-button-attach-ref';
16
18
  import { sideNavToggleTooltipKeyboardShortcut } from './side-nav-toggle-tooltip-keyboard-shortcut';
@@ -93,12 +95,17 @@ export var SideNavToggleButton = function SideNavToggleButton(_ref) {
93
95
  });
94
96
  var _useAnalyticsEvents = useAnalyticsEvents(),
95
97
  createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
96
- var openLayerObserver = useOpenLayerObserver();
98
+ var openLayerObserver = useOpenLayerObserver({
99
+ isEnabled: !fg('platform-dst-top-layer')
100
+ });
97
101
  var handleClick = useCallback(function (event, analyticsEvent) {
98
102
  onClick === null || onClick === void 0 || onClick(event, analyticsEvent, {
99
103
  isSideNavVisible: isSideNavExpanded
100
104
  });
101
105
  toggleVisibility();
106
+
107
+ // Not gated. Top-layer tooltips (`platform-dst-top-layer-tooltip`) are not known to the observer.
108
+ requestClosePopovers();
102
109
  openLayerObserver === null || openLayerObserver === void 0 || openLayerObserver.closeLayers();
103
110
  }, [isSideNavExpanded, onClick, openLayerObserver, toggleVisibility]);
104
111
  var handlePointerEnter = useCallback(function () {
@@ -2,6 +2,9 @@ import { useEffect } from 'react';
2
2
  import { bind } from 'bind-event-listener';
3
3
  import useStableRef from '@atlaskit/ds-lib/use-stable-ref';
4
4
  import { useOpenLayerObserver } from '@atlaskit/layering/use-open-layer-observer';
5
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
6
+ import { hasOpenDialogOrPopover } from '@atlaskit/top-layer/page-surface/has-open-dialog-or-popover';
7
+ import { requestClosePopovers } from '@atlaskit/top-layer/page-surface/request-close-popovers';
5
8
  import { useIsSideNavShortcutEnabled } from './use-is-side-nav-shortcut-enabled';
6
9
  import { useToggleSideNav } from './use-toggle-side-nav';
7
10
 
@@ -10,7 +13,9 @@ import { useToggleSideNav } from './use-toggle-side-nav';
10
13
  */
11
14
  export function useSideNavToggleKeyboardShortcut(_ref) {
12
15
  var canToggleWithShortcut = _ref.canToggleWithShortcut;
13
- var openLayerObserver = useOpenLayerObserver();
16
+ var openLayerObserver = useOpenLayerObserver({
17
+ isEnabled: !fg('platform-dst-top-layer')
18
+ });
14
19
  var toggleVisibilityByShortcut = useToggleSideNav({
15
20
  trigger: 'keyboard'
16
21
  });
@@ -33,12 +38,21 @@ export function useSideNavToggleKeyboardShortcut(_ref) {
33
38
  // Ignore repeated keydown events from holding down the keys
34
39
  return;
35
40
  }
41
+ if (fg('platform-dst-top-layer') && hasOpenDialogOrPopover({
42
+ type: 'modal'
43
+ })) {
44
+ // Return early if there are any open modal dialogs
45
+ return;
46
+ }
36
47
  if (openLayerObserver && openLayerObserver.getCount({
37
48
  type: 'modal'
38
49
  }) > 0) {
39
50
  // Return early if there are any open modals
40
51
  return;
41
52
  }
53
+
54
+ // Not gated. Top-layer tooltips (`platform-dst-top-layer-tooltip`) are not known to the observer.
55
+ requestClosePopovers();
42
56
  openLayerObserver === null || openLayerObserver === void 0 || openLayerObserver.closeLayers();
43
57
  toggleVisibilityByShortcut();
44
58
  }
@@ -66,7 +66,8 @@ export function TopNavEnd(_ref) {
66
66
 
67
67
  // The shared provider also covers the mobile overflow popup itself. Keep the
68
68
  // previous content-only namespace coverage when the layout gate is disabled.
69
- var actions = fg('platform-dst-chat-panel-layout') ? children : /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
69
+ // The observer is not used when the top-layer gate is on, so no provider is needed.
70
+ var actions = fg('platform-dst-chat-panel-layout') || fg('platform-dst-top-layer') ? children : /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
70
71
  namespace: openLayerObserverTopNavEndNamespace
71
72
  }, children);
72
73
  var content = /*#__PURE__*/React.createElement("nav", {
@@ -104,7 +105,7 @@ export function TopNavEnd(_ref) {
104
105
  }) : /*#__PURE__*/React.createElement(List, {
105
106
  xcss: cx(listStyles.root, listStyles.hideOnSmallViewport)
106
107
  }, actions), hasPersistentItems && persistentItems);
107
- return fg('platform-dst-chat-panel-layout') ? /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
108
+ return fg('platform-dst-chat-panel-layout') && !fg('platform-dst-top-layer') ? /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
108
109
  namespace: openLayerObserverTopNavEndNamespace
109
110
  }, content) : content;
110
111
  }
@@ -3,6 +3,7 @@ import "./top-nav-middle.compiled.css";
3
3
  import { ax, ix } from "@compiled/react/runtime";
4
4
  import React from 'react';
5
5
  import { OpenLayerObserverNamespaceProvider } from '@atlaskit/layering/open-layer-observer-namespace-provider';
6
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
6
7
  import { openLayerObserverTopNavMiddleNamespace } from '../constants';
7
8
  var styles = {
8
9
  root: "_zulpu2gc _yyhycs5v _1bsb1osq _4cvr1h6o _1e0c1txw _1bahh9n0 _181n11p5 _1j8b15b0 _lagd1bp4 _1t4c1ris _12e8h9n0"
@@ -20,7 +21,7 @@ export function TopNavMiddle(_ref) {
20
21
  var children = _ref.children;
21
22
  return /*#__PURE__*/React.createElement("div", {
22
23
  className: ax([styles.root])
23
- }, /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
24
+ }, fg('platform-dst-top-layer') ? children : /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
24
25
  namespace: openLayerObserverTopNavMiddleNamespace
25
26
  }, children));
26
27
  }
@@ -0,0 +1,3 @@
1
+ export { PanelLayout } from '../../ui/page-layout/panel-layout';
2
+ export type { PanelLayoutProps, PanelResizeEnd } from '../../ui/page-layout/panel-layout';
3
+ export { localPanelWidthVar } from '../../ui/page-layout/constants';
@@ -3,6 +3,10 @@
3
3
  * This violates the [UI styling standard](https://atlassian.design/components/eslint-plugin-ui-styling-standard/no-imported-style-values/usage).
4
4
  * We have chosen to ignore this rule to prevent duplicating them across the different slots, and to provide a high level view of them and how they relate.
5
5
  */
6
+ /**
7
+ * Default minimum width of Main, in pixels, before a custom minimum is registered.
8
+ */
9
+ export declare const defaultMainMinWidth = 320;
6
10
  export declare const sideNavVar = "--n_sNvw";
7
11
  export declare const asideVar = "--n_asDw";
8
12
  export declare const panelVar = "--n_pnlW";
@@ -12,6 +16,14 @@ export declare const mainMinimumWidthVar = "--n_mainMinW";
12
16
  export declare const bannerMountedVar = "--n_bnrM";
13
17
  export declare const topNavMountedVar = "--n_tNvM";
14
18
  export declare const ribbonVar = "--n_rbnW";
19
+ /**
20
+ * Rendered border-box width of the local PanelLayout surface, in both inline and overlay modes.
21
+ * Published on document.documentElement after mounting when Root opts into
22
+ * UNSAFE_dangerouslyHoistSlotSizes. Only the primary Root should opt in.
23
+ * Use `var(${localPanelWidthVar}, 0px)` for external controls, not for width persistence
24
+ * or sizing the panel itself. The property is removed when the surface unmounts.
25
+ */
26
+ export declare const localPanelWidthVar = "--n_localPanelWidth";
15
27
  /**
16
28
  * Captures the current width of the side navigation, at all times, including during resizing.
17
29
  *
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Local-panel defaults in pixels, used only when no explicit preference exists.
3
+ * Keep the existing desktop width until chat layout rolls out. Compact sizing is independent.
4
+ * These are requested defaults, not measurements of an open panel.
5
+ */
6
+ export declare function getPanelLayoutDefaults(): {
7
+ panelWidth: number;
8
+ compactPanelWidth: number;
9
+ panelMinWidth: number;
10
+ };
@@ -16,7 +16,11 @@ export type LayoutAreaConfig = {
16
16
  onRequestClose?: () => void;
17
17
  };
18
18
  export type StoredLayoutArea = LayoutAreaConfig & {
19
- preferredInlineWidth?: number;
19
+ /**
20
+ * Local panels share this preference across inline and overlay modes.
21
+ * SideNav and ChatPanel retain separate overlay preferences.
22
+ */
23
+ preferredWidth?: number;
20
24
  preferredOverlayWidth?: number;
21
25
  liveResize?: {
22
26
  mode: LayoutAreaMode;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @jsxRuntime classic
3
+ * @jsx jsx
4
+ */
5
+ import { type Key, type MutableRefObject, type ReactNode } from 'react';
6
+ import type { LayoutAreaMode, LayoutAreaState } from './layout-area-sizing-context';
7
+ import type { PanelResizeEnd } from './panel-layout';
8
+ import type { ResizeBounds } from './panel-splitter/types';
9
+ type LocalPanelSurfaceProps = {
10
+ children: ReactNode;
11
+ contentKey?: Key;
12
+ label: string;
13
+ resizeLabel: string;
14
+ defaultWidth: number;
15
+ minWidth: number;
16
+ maxWidth?: number;
17
+ testId?: string;
18
+ layoutRef: MutableRefObject<HTMLDivElement | null>;
19
+ managedSizing?: LayoutAreaState;
20
+ getManagedResizeBounds: () => ResizeBounds | undefined;
21
+ prepareResize?: () => Promise<boolean>;
22
+ onManagedResizeStart: (mode: LayoutAreaMode) => void;
23
+ onManagedResize: (mode: LayoutAreaMode, width: number) => void;
24
+ onManagedResizeEnd: (mode: LayoutAreaMode, width: number) => void;
25
+ onWidthChange: (width: number) => void;
26
+ onResizeEnd: (event: PanelResizeEnd) => void;
27
+ };
28
+ /**
29
+ * Internal surface for PanelLayout. The host supplies content; navigation owns its geometry.
30
+ */
31
+ export declare function LocalPanelSurface({ children, contentKey, label, resizeLabel, defaultWidth, minWidth, maxWidth, testId, layoutRef, managedSizing, getManagedResizeBounds, prepareResize, onManagedResizeStart, onManagedResize, onManagedResizeEnd, onWidthChange, onResizeEnd, }: LocalPanelSurfaceProps): JSX.Element;
32
+ export {};
@@ -0,0 +1,2 @@
1
+ import { type Context } from 'react';
2
+ export declare const MainMinWidthContext: Context<number>;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @jsxRuntime classic
3
+ * @jsx jsx
4
+ */
5
+ import { type MutableRefObject, type ReactNode } from 'react';
6
+ import type { LayoutAreaMode } from './layout-area-sizing-context';
7
+ type PanelLayoutShellProps = {
8
+ /**
9
+ * Main content rendered alongside the local panel.
10
+ */
11
+ children: ReactNode;
12
+ /**
13
+ * Panel content or surface supplied by the caller.
14
+ */
15
+ panel: ReactNode;
16
+ /**
17
+ * Whether the local panel is open.
18
+ */
19
+ isPanelOpen: boolean;
20
+ /**
21
+ * Effective panel track width in pixels.
22
+ */
23
+ panelWidth: number;
24
+ compactPanelWidth: number;
25
+ /**
26
+ * Minimum panel width in pixels.
27
+ */
28
+ panelMinWidth?: number;
29
+ /**
30
+ * Allocated placement. Before measurement, CSS reserves a track when both minimums fit the host.
31
+ */
32
+ mode?: LayoutAreaMode;
33
+ /**
34
+ * Shared with the panel's resize controls so imperative resizing also updates the grid track.
35
+ */
36
+ layoutRef?: MutableRefObject<HTMLDivElement | null>;
37
+ /**
38
+ * Clips the layout during panel motion.
39
+ */
40
+ shouldClipOverflow?: boolean;
41
+ testId?: string;
42
+ };
43
+ /**
44
+ * Grid and scrolling for Main and its local panel. Use inside navigation's Root and Main.
45
+ */
46
+ export declare function PanelLayoutShell({ children, panel, isPanelOpen, panelWidth, compactPanelWidth, panelMinWidth, mode, layoutRef, shouldClipOverflow, testId, }: PanelLayoutShellProps): JSX.Element;
47
+ export {};
@@ -0,0 +1,74 @@
1
+ import { type Key, type ReactNode } from 'react';
2
+ import { type LayoutAreaMode } from './layout-area-sizing-context';
3
+ export type PanelResizeEnd = {
4
+ initialWidth: number;
5
+ finalWidth: number;
6
+ mode: LayoutAreaMode;
7
+ };
8
+ export type PanelLayoutProps = {
9
+ /**
10
+ * Main content. Mount PanelLayout inside navigation's Main, alongside ChatPanel in Root.
11
+ */
12
+ children: ReactNode;
13
+ /**
14
+ * Caller-owned panel content; no Panel System provider or renderer is required.
15
+ */
16
+ panel: ReactNode;
17
+ isPanelOpen: boolean;
18
+ /**
19
+ * Optional content identity, used to reset scrolling and animate content replacement.
20
+ */
21
+ panelKey?: Key;
22
+ /**
23
+ * Controlled preferred width in pixels. Allocation may constrain it without changing the request.
24
+ */
25
+ panelWidth?: number;
26
+ /**
27
+ * Initial preferred width in pixels; subsequent changes are ignored.
28
+ * Defaults to 365, or 400 with chat layout enabled.
29
+ * After a user resize, one preferred width is retained across inline and overlay modes.
30
+ * Available space can constrain the rendered width without overwriting that preference.
31
+ */
32
+ defaultPanelWidth?: number;
33
+ /**
34
+ * Default at compact viewport sizes. Defaults to 320, or an explicitly supplied defaultPanelWidth.
35
+ * Used only until a controlled width or user resize supplies a preference.
36
+ */
37
+ compactDefaultPanelWidth?: number;
38
+ /**
39
+ * Minimum width in pixels. Defaults to 320; overlays can be smaller in a narrower container.
40
+ */
41
+ panelMinWidth?: number;
42
+ /**
43
+ * Optional maximum width in pixels.
44
+ */
45
+ panelMaxWidth?: number;
46
+ /**
47
+ * Called after user resizing, with the effective width. Accept this value to control panelWidth.
48
+ */
49
+ onPanelWidthChange?: (width: number) => void;
50
+ /**
51
+ * One callback per completed pointer/keyboard resize, for persistence and analytics.
52
+ */
53
+ onResizeEnd?: (event: PanelResizeEnd) => void;
54
+ /**
55
+ * Accessible region and splitter labels; pass localized values in products.
56
+ */
57
+ panelLabel?: string;
58
+ resizeLabel?: string;
59
+ testId?: string;
60
+ };
61
+ /**
62
+ * A coordinated local panel with caller-owned content and state. Keep this host mounted
63
+ * while closed to retain resized widths. Unmount it to reset its width preferences.
64
+ *
65
+ * Mount only one local-panel host per navigation Root/sizing coordinator, including
66
+ * closed hosts and panel-system's LayoutWithPanel. Switch content through the same host;
67
+ * separate Roots may each own a local panel.
68
+ *
69
+ * With chat layout enabled it shares Root's sizing coordinator. Otherwise it measures
70
+ * its own Main region, leaving existing navigation/chat behavior unchanged.
71
+ * Local-panel placement and resize constraints use this layout in both cases; disabling
72
+ * the chat-layout gate does not restore the previous panel-system layout engine.
73
+ */
74
+ export declare function PanelLayout(props: PanelLayoutProps): JSX.Element;