@elastic/eui 122.1.0 → 123.0.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 (46) hide show
  1. package/dist/eui-icons.json +94 -94
  2. package/es/components/datagrid/body/data_grid_body_virtualized.js +119 -36
  3. package/es/components/datagrid/utils/row_heights.js +4 -1
  4. package/es/components/flyout/flyout.component.js +129 -55
  5. package/es/components/flyout/flyout_menu/action_button.js +15 -21
  6. package/es/components/flyout/flyout_menu/flyout_menu.js +40 -46
  7. package/es/components/flyout/manager/flyout_managed.js +24 -6
  8. package/es/components/form/described_form_group/described_form_group.js +17 -4
  9. package/es/components/tabs/tabbed_content/tabbed_content.js +93 -138
  10. package/es/components/text_truncate/text_truncate.js +9 -4
  11. package/eui.d.ts +32 -58
  12. package/lib/components/datagrid/body/data_grid_body_virtualized.js +119 -36
  13. package/lib/components/datagrid/utils/row_heights.js +4 -1
  14. package/lib/components/flyout/flyout.component.js +134 -62
  15. package/lib/components/flyout/flyout_menu/action_button.js +18 -23
  16. package/lib/components/flyout/flyout_menu/flyout_menu.js +40 -46
  17. package/lib/components/flyout/manager/flyout_managed.js +23 -5
  18. package/lib/components/form/described_form_group/described_form_group.js +19 -3
  19. package/lib/components/tabs/tabbed_content/tabbed_content.js +98 -142
  20. package/lib/components/text_truncate/text_truncate.js +9 -4
  21. package/optimize/es/components/datagrid/body/data_grid_body_virtualized.js +116 -36
  22. package/optimize/es/components/datagrid/utils/row_heights.js +4 -1
  23. package/optimize/es/components/flyout/flyout.component.js +124 -50
  24. package/optimize/es/components/flyout/flyout_menu/action_button.js +14 -21
  25. package/optimize/es/components/flyout/manager/flyout_managed.js +24 -6
  26. package/optimize/es/components/form/described_form_group/described_form_group.js +17 -4
  27. package/optimize/es/components/tabs/tabbed_content/tabbed_content.js +87 -131
  28. package/optimize/es/components/text_truncate/text_truncate.js +4 -3
  29. package/optimize/lib/components/datagrid/body/data_grid_body_virtualized.js +116 -36
  30. package/optimize/lib/components/datagrid/utils/row_heights.js +4 -1
  31. package/optimize/lib/components/flyout/flyout.component.js +123 -49
  32. package/optimize/lib/components/flyout/flyout_menu/action_button.js +14 -22
  33. package/optimize/lib/components/flyout/manager/flyout_managed.js +23 -5
  34. package/optimize/lib/components/form/described_form_group/described_form_group.js +19 -3
  35. package/optimize/lib/components/tabs/tabbed_content/tabbed_content.js +87 -131
  36. package/optimize/lib/components/text_truncate/text_truncate.js +4 -3
  37. package/package.json +2 -2
  38. package/test-env/components/datagrid/body/data_grid_body_virtualized.js +119 -36
  39. package/test-env/components/datagrid/utils/row_heights.js +4 -1
  40. package/test-env/components/flyout/flyout.component.js +123 -49
  41. package/test-env/components/flyout/flyout_menu/action_button.js +14 -22
  42. package/test-env/components/flyout/flyout_menu/flyout_menu.js +40 -46
  43. package/test-env/components/flyout/manager/flyout_managed.js +23 -5
  44. package/test-env/components/form/described_form_group/described_form_group.js +19 -3
  45. package/test-env/components/tabs/tabbed_content/tabbed_content.js +88 -132
  46. package/test-env/components/text_truncate/text_truncate.js +9 -4
@@ -1,8 +1,8 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
3
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
5
4
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
5
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
6
6
  var _excluded = ["className", "children", "as", "hideCloseButton", "flyoutMenuProps", "flyoutMenuDisplayMode", "closeButtonProps", "closeButtonPosition", "onClose", "ownFocus", "side", "size", "paddingSize", "maxWidth", "style", "hasChildBackground", "maskProps", "type", "outsideClickCloses", "pushMinBreakpoint", "pushAnimation", "hasAnimation", "focusTrapProps", "includeFixedHeadersInFocusTrap", "includeSelectorInFocusTrap", "aria-describedby", "aria-labelledby", "id", "resizable", "minWidth", "onResize", "onAnimationEnd", "container"];
7
7
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
8
8
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -18,7 +18,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
18
18
 
19
19
  import React, { useEffect, useLayoutEffect, useRef, useMemo, useCallback, useState, forwardRef } from 'react';
20
20
  import classnames from 'classnames';
21
- import { keys, EuiWindowEvent, useCombinedRefs, useEuiTheme, useEuiMemoizedStyles, useGeneratedHtmlId, useEuiThemeCSSVariables, focusTrapPubSub } from '../../services';
21
+ import { keys, EuiWindowEvent, useCombinedRefs, useEuiTheme, useEuiMemoizedStyles, useGeneratedHtmlId, focusTrapPubSub } from '../../services';
22
22
  import { useIsInManagedFlyout, useFlyoutId, useFlyoutManager } from './manager';
23
23
  import { LAYOUT_MODE_SIDE_BY_SIDE, LAYOUT_MODE_STACKED, LEVEL_MAIN, PROPERTY_LEVEL } from './manager/const';
24
24
  import { EuiFocusTrap } from '../focus_trap';
@@ -53,6 +53,52 @@ var resolveContainer = function resolveContainer(raw) {
53
53
  if (typeof HTMLElement === 'undefined') return null;
54
54
  return raw instanceof HTMLElement ? raw : null;
55
55
  };
56
+
57
+ /**
58
+ * Per-target push-flyout offset bookkeeping, shared across every flyout React root (they all
59
+ * render from this one module). Keyed by the element the offset is applied to — a `container` or
60
+ * `document.body` — so flyouts targeting different elements never contend.
61
+ *
62
+ * Instead of a single owner per side, every currently-pushed flyout records its width as a
63
+ * contribution and the applied offset is derived from the set (the widest contribution). Closing,
64
+ * resizing, or backgrounding any one flyout just updates its own entry, so the result no longer
65
+ * depends on open/close order or on cross-root effect ordering. The target's base (pre-flyout)
66
+ * inline padding is captured when the first contribution arrives and restored when the last one
67
+ * leaves. See https://github.com/elastic/eui/issues/9788.
68
+ */
69
+
70
+ var euiPushPaddingRegistry = new WeakMap();
71
+ var euiSideStyleKey = function euiSideStyleKey(side) {
72
+ return side === 'left' ? 'paddingInlineStart' : 'paddingInlineEnd';
73
+ };
74
+ var euiSideCssVarKey = function euiSideCssVarKey(side) {
75
+ return side === 'left' ? '--euiPushFlyoutOffsetInlineStart' : '--euiPushFlyoutOffsetInlineEnd';
76
+ };
77
+ var euiGetPushPaddingSideState = function euiGetPushPaddingSideState(target, side) {
78
+ var state = euiPushPaddingRegistry.get(target);
79
+ if (!state) {
80
+ state = {
81
+ left: {
82
+ base: '',
83
+ contributions: new Map()
84
+ },
85
+ right: {
86
+ base: '',
87
+ contributions: new Map()
88
+ }
89
+ };
90
+ euiPushPaddingRegistry.set(target, state);
91
+ }
92
+ return state[side];
93
+ };
94
+ var euiMaxContribution = function euiMaxContribution(contributions) {
95
+ var filter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
96
+ return true;
97
+ };
98
+ return Math.max.apply(Math, [0].concat(_toConsumableArray(Array.from(contributions.values(), function (contribution) {
99
+ return filter(contribution) ? contribution.width : 0;
100
+ }))));
101
+ };
56
102
  var defaultElement = 'div';
57
103
  export var EuiFlyoutComponent = /*#__PURE__*/forwardRef(function (props, ref) {
58
104
  var _maskProps$headerZind, _managerSessions, _managerState$layoutM, _managerState$current, _managerState$flyouts, _managerState$pushPad;
@@ -107,8 +153,6 @@ export var EuiFlyoutComponent = /*#__PURE__*/forwardRef(function (props, ref) {
107
153
  var container = resolveContainer(containerProp);
108
154
  var hasAnimationDefault = type === 'overlay';
109
155
  var hasAnimation = _hasAnimation !== null && _hasAnimation !== void 0 ? _hasAnimation : hasAnimationDefault;
110
- var _useEuiThemeCSSVariab = useEuiThemeCSSVariables(),
111
- setGlobalCSSVariables = _useEuiThemeCSSVariab.setGlobalCSSVariables;
112
156
  var Element = as || defaultElement;
113
157
  var maskRef = useRef(null);
114
158
 
@@ -125,10 +169,6 @@ export var EuiFlyoutComponent = /*#__PURE__*/forwardRef(function (props, ref) {
125
169
  pushMinBreakpoint: pushMinBreakpoint,
126
170
  containerWidth: containerReferenceWidth
127
171
  });
128
- // When no explicit container is provided, push padding targets
129
- // document.body and global push-offset CSS vars are set. When a
130
- // container is provided, only that element receives padding.
131
- var shouldSetGlobalPushVars = container == null;
132
172
  if ('container' in props && ('maskProps' in props || 'includeFixedHeadersInFocusTrap' in props) && process.env.NODE_ENV === 'development') {
133
173
  if ('maskProps' in props) {
134
174
  console.warn('EuiFlyout: `maskProps` is deprecated. Prefer using the `container` prop to scope flyouts.');
@@ -199,22 +239,33 @@ export var EuiFlyoutComponent = /*#__PURE__*/forwardRef(function (props, ref) {
199
239
  }
200
240
  }, [isInManagedContext, flyoutId]);
201
241
 
202
- // Derive flyout identity and sibling info from the single context read
242
+ // Derive flyout identity and sibling info from the session this flyout
243
+ // belongs to. Not the current (top-most) session: a newly opened main
244
+ // renders once before it registers its own session, and a backgrounded
245
+ // main is not in the current session at all. Reading the current session
246
+ // in those cases would treat the other session's main as this flyout's
247
+ // sibling and clamp the resizable width against it.
248
+ var ownSession = useMemo(function () {
249
+ var _managerSessions$find;
250
+ return (_managerSessions$find = managerSessions === null || managerSessions === void 0 ? void 0 : managerSessions.find(function (session) {
251
+ return session.mainFlyoutId === flyoutId || session.childFlyoutId === flyoutId;
252
+ })) !== null && _managerSessions$find !== void 0 ? _managerSessions$find : null;
253
+ }, [managerSessions, flyoutId]);
203
254
  var flyoutIdentity = useMemo(function () {
204
- if (!flyoutId || !currentSession) {
255
+ if (!flyoutId || !ownSession) {
205
256
  return {
206
257
  isMainFlyout: false,
207
258
  siblingFlyoutId: null,
208
259
  hasValidSession: false
209
260
  };
210
261
  }
211
- var siblingFlyoutId = currentSession.mainFlyoutId === flyoutId ? currentSession.childFlyoutId : currentSession.mainFlyoutId;
262
+ var siblingFlyoutId = ownSession.mainFlyoutId === flyoutId ? ownSession.childFlyoutId : ownSession.mainFlyoutId;
212
263
  return {
213
- isMainFlyout: currentSession.mainFlyoutId === flyoutId,
264
+ isMainFlyout: ownSession.mainFlyoutId === flyoutId,
214
265
  siblingFlyoutId: siblingFlyoutId,
215
266
  hasValidSession: true
216
267
  };
217
- }, [flyoutId, currentSession]);
268
+ }, [flyoutId, ownSession]);
218
269
 
219
270
  // Destructure for easier use
220
271
  var siblingFlyoutId = flyoutIdentity.siblingFlyoutId,
@@ -295,17 +346,24 @@ export var EuiFlyoutComponent = /*#__PURE__*/forwardRef(function (props, ref) {
295
346
  // the document element so that the child (fill) flyout can track it
296
347
  // synchronously during drag resize, avoiding the 1-frame lag that
297
348
  // results from the async ResizeObserver → manager-state pipeline.
349
+ // Only the active session's main publishes: a backgrounded main keeps its
350
+ // `isMainFlyout` role but must not leave its width behind for the new
351
+ // session's child to read.
298
352
  useLayoutEffect(function () {
299
- if (!isMainFlyout) return;
353
+ if (!isMainFlyout || !isActiveManagedFlyout) return;
300
354
 
301
355
  // Only set when we have a computed percentage (during active resize)
302
- if (typeof size === 'string' && size.endsWith('%')) {
303
- document.documentElement.style.setProperty('--euiFlyoutMainWidth', size);
304
- }
356
+ if (typeof size !== 'string' || !size.endsWith('%')) return;
357
+ var style = document.documentElement.style;
358
+ style.setProperty('--euiFlyoutMainWidth', size);
305
359
  return function () {
306
- document.documentElement.style.removeProperty('--euiFlyoutMainWidth');
360
+ // Flyouts in separate React roots can run this cleanup after another
361
+ // main has already published its own width; leave that value alone.
362
+ if (style.getPropertyValue('--euiFlyoutMainWidth') === size) {
363
+ style.removeProperty('--euiFlyoutMainWidth');
364
+ }
307
365
  };
308
- }, [isMainFlyout, size]);
366
+ }, [isMainFlyout, isActiveManagedFlyout, size]);
309
367
 
310
368
  /**
311
369
  * Setting up the refs on the actual flyout element in order to
@@ -325,45 +383,61 @@ export var EuiFlyoutComponent = /*#__PURE__*/forwardRef(function (props, ref) {
325
383
  * Uses useLayoutEffect so padding is applied before child render.
326
384
  */
327
385
  useLayoutEffect(function () {
328
- if (!isPushed) {
329
- return;
330
- }
331
386
  var paddingTarget = container !== null && container !== void 0 ? container : document.body;
332
- var shouldApplyPadding = !isInManagedContext || isActiveManagedFlyout;
333
- var paddingSide = side === 'left' ? 'paddingInlineStart' : 'paddingInlineEnd';
334
- var cssVarName = "--euiPushFlyoutOffset".concat(side === 'left' ? 'InlineStart' : 'InlineEnd');
335
387
  var managerSide = side === 'left' ? 'left' : 'right';
388
+ var styleKey = euiSideStyleKey(managerSide);
389
+ var state = euiGetPushPaddingSideState(paddingTarget, managerSide);
336
390
 
337
- // Capture pre-existing inline padding so it can be restored on cleanup
338
- var previousPadding = paddingTarget.style[paddingSide];
339
- var paddingWidth = layoutMode === LAYOUT_MODE_STACKED && isMainFlyout && _siblingFlyoutWidth ? _siblingFlyoutWidth : width;
340
- if (shouldApplyPadding) {
341
- paddingTarget.style[paddingSide] = "".concat(paddingWidth, "px");
342
- if (shouldSetGlobalPushVars) {
343
- setGlobalCSSVariables(_defineProperty({}, cssVarName, "".concat(paddingWidth, "px")));
344
- }
345
- if (isInManagedContext && flyoutManagerRef.current) {
346
- flyoutManagerRef.current.setPushPadding(managerSide, paddingWidth);
347
- }
348
- } else {
349
- paddingTarget.style[paddingSide] = previousPadding;
350
- if (shouldSetGlobalPushVars) {
351
- setGlobalCSSVariables(_defineProperty({}, cssVarName, null));
391
+ // Write the offset derived from all current contributions: the widest pushed flyout on
392
+ // this target.
393
+ var apply = function apply() {
394
+ var total = euiMaxContribution(state.contributions);
395
+ var isPushing = state.contributions.size > 0;
396
+ paddingTarget.style[styleKey] = isPushing ? "".concat(total, "px") : state.base;
397
+ // Without a `container` the offset is also exposed as a global CSS variable. It is
398
+ // written inline on `<html>` rather than through `EuiProvider`, because every React root
399
+ // has its own provider rendering its own `:root` block and the last one inserted would
400
+ // win regardless of which root's flyouts are still open.
401
+ if (container == null) {
402
+ var cssVar = euiSideCssVarKey(managerSide);
403
+ if (isPushing) {
404
+ document.documentElement.style.setProperty(cssVar, "".concat(total, "px"));
405
+ } else {
406
+ document.documentElement.style.removeProperty(cssVar);
407
+ }
352
408
  }
353
- if (isInManagedContext && flyoutManagerRef.current) {
354
- flyoutManagerRef.current.setPushPadding(managerSide, 0);
409
+ // The manager only learns about managed flyouts, so it must not be told about a standalone
410
+ // flyout's width: nothing would ever reset it once that flyout closes.
411
+ if (isInManagedContext) {
412
+ var _flyoutManagerRef$cur5;
413
+ (_flyoutManagerRef$cur5 = flyoutManagerRef.current) === null || _flyoutManagerRef$cur5 === void 0 || _flyoutManagerRef$cur5.setPushPadding(managerSide, euiMaxContribution(state.contributions, function (c) {
414
+ return c.managed;
415
+ }));
355
416
  }
417
+ };
418
+ var paddingWidth = layoutMode === LAYOUT_MODE_STACKED && isMainFlyout && _siblingFlyoutWidth ? _siblingFlyoutWidth : width;
419
+
420
+ // A standalone flyout pushes whenever it is in push mode. A managed flyout only pushes while
421
+ // it is the active session's flyout; a backgrounded push flyout (e.g. under a new overlay
422
+ // session) withdraws its contribution so the page is not left pushed for it.
423
+ var shouldPush = isPushed && (!isInManagedContext || isActiveManagedFlyout);
424
+ if (!shouldPush) {
425
+ return;
356
426
  }
427
+ if (state.contributions.size === 0) {
428
+ // First pushed flyout on this side: capture the app's own inline padding to restore later.
429
+ state.base = paddingTarget.style[styleKey];
430
+ }
431
+ state.contributions.set(flyoutId, {
432
+ width: paddingWidth,
433
+ managed: isInManagedContext
434
+ });
435
+ apply();
357
436
  return function () {
358
- paddingTarget.style[paddingSide] = previousPadding;
359
- if (shouldSetGlobalPushVars) {
360
- setGlobalCSSVariables(_defineProperty({}, cssVarName, null));
361
- }
362
- if (isInManagedContext && flyoutManagerRef.current) {
363
- flyoutManagerRef.current.setPushPadding(managerSide, 0);
364
- }
437
+ state.contributions.delete(flyoutId);
438
+ apply();
365
439
  };
366
- }, [isPushed, isInManagedContext, isActiveManagedFlyout, setGlobalCSSVariables, side, width, layoutMode, isMainFlyout, _siblingFlyoutWidth, shouldSetGlobalPushVars, container]);
440
+ }, [isPushed, isInManagedContext, isActiveManagedFlyout, side, width, layoutMode, isMainFlyout, _siblingFlyoutWidth, container, flyoutId]);
367
441
 
368
442
  /**
369
443
  * This class doesn't actually do anything by EUI, but is nice to add for consumers (JIC)
@@ -1,4 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
+ var _excluded = ["toolTipContent", "toolTipProps"];
2
4
  /*
3
5
  * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
4
6
  * or more contributor license agreements. Licensed under the Elastic License
@@ -13,29 +15,20 @@ import { EuiToolTip } from '../../tool_tip';
13
15
  import { jsx as ___EmotionJSX } from "@emotion/react";
14
16
  export var MenuActionButton = function MenuActionButton(_ref) {
15
17
  var action = _ref.action;
16
- var iconType = action.iconType,
17
- onClick = action.onClick,
18
- ariaLabel = action['aria-label'],
19
- toolTipContent = action.toolTipContent,
18
+ var toolTipContent = action.toolTipContent,
20
19
  toolTipProps = action.toolTipProps,
21
- isDisabled = action.isDisabled,
22
- isLoading = action.isLoading,
23
- href = action.href,
24
- target = action.target;
25
- var sharedProps = {
26
- 'aria-label': ariaLabel,
27
- iconType: iconType,
28
- onClick: onClick,
29
- color: 'text',
30
- size: 'xs',
31
- isDisabled: isDisabled,
32
- // Keeps the button focusable so tooltip-on-disabled works for keyboard users
33
- isLoading: isLoading,
34
- href: href,
35
- target: target
36
- };
20
+ buttonProps = _objectWithoutProperties(action, _excluded);
21
+ var button = ___EmotionJSX(EuiButtonIcon, _extends({}, buttonProps, {
22
+ // The menu bar sets these props itself so every action looks the same.
23
+ // Anything set here also belongs in `EuiFlyoutMenuOwnedActionProps`.
24
+ color: "text",
25
+ size: "xs",
26
+ display: "empty",
27
+ iconSize: "m",
28
+ isSelected: undefined
29
+ }));
37
30
  return toolTipContent ? ___EmotionJSX(EuiToolTip, _extends({
38
31
  content: toolTipContent,
39
32
  disableScreenReaderOutput: true
40
- }, toolTipProps), ___EmotionJSX(EuiButtonIcon, sharedProps)) : ___EmotionJSX(EuiButtonIcon, sharedProps);
33
+ }, toolTipProps), button) : button;
41
34
  };
@@ -14,7 +14,7 @@ function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringif
14
14
  * Side Public License, v 1.
15
15
  */
16
16
 
17
- import React, { useEffect, useLayoutEffect, useMemo, useRef, useState, forwardRef } from 'react';
17
+ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, forwardRef } from 'react';
18
18
  import { css } from '@emotion/react';
19
19
  import { flushSync } from 'react-dom';
20
20
  import { useCombinedRefs, useEuiMemoizedStyles } from '../../../services';
@@ -167,6 +167,24 @@ export var EuiManagedFlyout = /*#__PURE__*/forwardRef(function (_ref2, ref) {
167
167
  flyoutExistsInManagerRef.current = flyoutExistsInManager;
168
168
  }, [flyoutExistsInManager]);
169
169
 
170
+ // Closing a main closes its whole history group via `closeAllFlyouts`, which always targets
171
+ // the *current* session. A main that has been backgrounded by a newer session (e.g. closed
172
+ // programmatically from another React root) must only remove its own session, otherwise it
173
+ // tears down the foreground session and leaves its own stale session behind.
174
+ var closeOwnFlyouts = useCallback(function () {
175
+ if (level !== LEVEL_MAIN) {
176
+ closeFlyout(flyoutId);
177
+ return;
178
+ }
179
+ var _getFlyoutManagerStor = getFlyoutManagerStore().getState(),
180
+ sessions = _getFlyoutManagerStor.sessions;
181
+ var ownSession = sessions.find(function (session) {
182
+ return session.mainFlyoutId === flyoutId;
183
+ });
184
+ var isBackgroundedMain = ownSession != null && ownSession !== sessions[sessions.length - 1];
185
+ isBackgroundedMain ? closeFlyout(flyoutId) : closeAllFlyouts();
186
+ }, [level, flyoutId, closeFlyout, closeAllFlyouts]);
187
+
170
188
  // Register with flyout manager context when open, remove when closed
171
189
  // Using useLayoutEffect to run synchronously before DOM updates
172
190
  useLayoutEffect(function () {
@@ -178,7 +196,7 @@ export var EuiManagedFlyout = /*#__PURE__*/forwardRef(function (_ref2, ref) {
178
196
  });
179
197
  if (stillInStore) {
180
198
  // Normal cleanup (deps changed or explicit close via isOpen=false)
181
- level === LEVEL_MAIN ? closeAllFlyouts() : closeFlyout(flyoutId);
199
+ closeOwnFlyouts();
182
200
  } else if (wasRegisteredRef.current) {
183
201
  var _onCloseCallbackRef$c, _store$consumeCloseMe;
184
202
  // Removed externally while mounted: forward the store-stamped reason
@@ -189,7 +207,7 @@ export var EuiManagedFlyout = /*#__PURE__*/forwardRef(function (_ref2, ref) {
189
207
  }
190
208
  wasRegisteredRef.current = false;
191
209
  };
192
- }, [flyoutId, title, level, size, minWidth, historyKey, _flyoutMenuProps === null || _flyoutMenuProps === void 0 ? void 0 : _flyoutMenuProps.iconType, addFlyout, closeFlyout, closeAllFlyouts]);
210
+ }, [flyoutId, title, level, size, minWidth, historyKey, _flyoutMenuProps === null || _flyoutMenuProps === void 0 ? void 0 : _flyoutMenuProps.iconType, addFlyout, closeOwnFlyouts]);
193
211
 
194
212
  // Detect when flyout has been removed from manager state (e.g., via Back button)
195
213
  // and trigger onClose callback to notify the parent component
@@ -204,8 +222,8 @@ export var EuiManagedFlyout = /*#__PURE__*/forwardRef(function (_ref2, ref) {
204
222
  // any other removal (e.g. a closeAllFlyouts cascade reaching a backgrounded
205
223
  // flyout) defaults to `navigation-cascade`.
206
224
  if (wasRegisteredRef.current && !flyoutExistsInManager) {
207
- var _onCloseCallbackRef$c2, _getFlyoutManagerStor;
208
- (_onCloseCallbackRef$c2 = onCloseCallbackRef.current) === null || _onCloseCallbackRef$c2 === void 0 || _onCloseCallbackRef$c2.call(onCloseCallbackRef, new MouseEvent('navigation'), (_getFlyoutManagerStor = getFlyoutManagerStore().consumeCloseMeta(flyoutId)) !== null && _getFlyoutManagerStor !== void 0 ? _getFlyoutManagerStor : {
225
+ var _onCloseCallbackRef$c2, _getFlyoutManagerStor2;
226
+ (_onCloseCallbackRef$c2 = onCloseCallbackRef.current) === null || _onCloseCallbackRef$c2 === void 0 || _onCloseCallbackRef$c2.call(onCloseCallbackRef, new MouseEvent('navigation'), (_getFlyoutManagerStor2 = getFlyoutManagerStore().consumeCloseMeta(flyoutId)) !== null && _getFlyoutManagerStor2 !== void 0 ? _getFlyoutManagerStor2 : {
209
227
  reason: 'navigation-cascade'
210
228
  });
211
229
  wasRegisteredRef.current = false; // Reset to avoid repeated calls
@@ -242,7 +260,7 @@ export var EuiManagedFlyout = /*#__PURE__*/forwardRef(function (_ref2, ref) {
242
260
  // and ensures cascade close logic runs before DOM cleanup begins
243
261
  // Using flushSync to force synchronous state update completion
244
262
  flushSync(function () {
245
- level === LEVEL_MAIN ? closeAllFlyouts() : closeFlyout(flyoutId);
263
+ closeOwnFlyouts();
246
264
  });
247
265
  if (onCloseCallbackRef.current) {
248
266
  var event = e || new MouseEvent('click');
@@ -1,6 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- var _excluded = ["children", "className", "gutterSize", "fullWidth", "ratio", "titleSize", "title", "description", "descriptionFlexItemProps", "fieldFlexItemProps"];
3
+ var _excluded = ["children", "className", "gutterSize", "fullWidth", "ratio", "titleSize", "title", "description", "descriptionFlexItemProps", "fieldFlexItemProps", "aria-label", "aria-labelledby"];
4
4
  /*
5
5
  * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
6
6
  * or more contributor license agreements. Licensed under the Elastic License
@@ -9,9 +9,9 @@ var _excluded = ["children", "className", "gutterSize", "fullWidth", "ratio", "t
9
9
  * Side Public License, v 1.
10
10
  */
11
11
 
12
- import React from 'react';
12
+ import React, { isValidElement } from 'react';
13
13
  import classNames from 'classnames';
14
- import { useEuiMemoizedStyles } from '../../../services';
14
+ import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services';
15
15
  import { EuiTitle } from '../../title';
16
16
  import { EuiText } from '../../text';
17
17
  import { EuiFlexGroup, EuiFlexItem } from '../../flex';
@@ -38,7 +38,15 @@ export var EuiDescribedFormGroup = function EuiDescribedFormGroup(props) {
38
38
  description = props.description,
39
39
  descriptionFlexItemProps = props.descriptionFlexItemProps,
40
40
  fieldFlexItemProps = props.fieldFlexItemProps,
41
+ ariaLabel = props['aria-label'],
42
+ ariaLabelledby = props['aria-labelledby'],
41
43
  rest = _objectWithoutProperties(props, _excluded);
44
+ var generatedTitleId = useGeneratedHtmlId({
45
+ prefix: 'euiDescribedFormGroupTitle'
46
+ });
47
+ // Reuse an `id` already set on the title element, so that consumers
48
+ // referencing it from their own `aria-labelledby` keep working
49
+ var titleId = /*#__PURE__*/isValidElement(title) && title.props.id || generatedTitleId;
42
50
  var styles = useEuiMemoizedStyles(euiDescribedFormGroupStyles);
43
51
  var cssStyles = [styles.euiDescribedFormGroup, fullWidth ? styles.fullWidth : styles.formWidth];
44
52
  var descriptionColumnStyles = [styles.euiDescribedFormGroup__descriptionColumn, descriptionFlexItemProps === null || descriptionFlexItemProps === void 0 ? void 0 : descriptionFlexItemProps.css];
@@ -72,7 +80,11 @@ export var EuiDescribedFormGroup = function EuiDescribedFormGroup(props) {
72
80
  break;
73
81
  }
74
82
  return ___EmotionJSX(EuiFlexGroup, _extends({
75
- role: "group"
83
+ role: "group",
84
+ "aria-label": ariaLabel
85
+ // The title names the group, unless the consumer provides their own label
86
+ ,
87
+ "aria-labelledby": ariaLabelledby !== null && ariaLabelledby !== void 0 ? ariaLabelledby : ariaLabel == null ? titleId : undefined
76
88
  }, rest, {
77
89
  css: cssStyles,
78
90
  className: classes,
@@ -84,6 +96,7 @@ export var EuiDescribedFormGroup = function EuiDescribedFormGroup(props) {
84
96
  css: descriptionColumnStyles,
85
97
  className: classNames('euiDescribedFormGroup__descriptionColumn', descriptionFlexItemProps === null || descriptionFlexItemProps === void 0 ? void 0 : descriptionFlexItemProps.className)
86
98
  }), ___EmotionJSX(EuiTitle, {
99
+ id: titleId,
87
100
  size: titleSize,
88
101
  className: "euiDescribedFormGroup__title"
89
102
  }, title), renderedDescription), ___EmotionJSX(EuiFlexItem, _extends({