@atlaskit/popup 6.3.3 → 6.3.5

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 (36) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/__tests__/playwright/fit-viewport.spec.tsx +225 -0
  3. package/dist/cjs/compositional/popup-content-top-layer.js +30 -19
  4. package/dist/cjs/compositional/popup.js +1 -1
  5. package/dist/cjs/compositional/trigger-ref-object-context.js +2 -2
  6. package/dist/cjs/internal/get-popup-axis-sizes.js +42 -0
  7. package/dist/cjs/popper-wrapper.js +1 -1
  8. package/dist/cjs/popup-top-layer.js +28 -20
  9. package/dist/cjs/popup.js +1 -1
  10. package/dist/cjs/use-appearance.js +11 -3
  11. package/dist/es2019/compositional/popup-content-top-layer.js +27 -18
  12. package/dist/es2019/compositional/popup.js +1 -1
  13. package/dist/es2019/compositional/trigger-ref-object-context.js +2 -2
  14. package/dist/es2019/internal/get-popup-axis-sizes.js +37 -0
  15. package/dist/es2019/popper-wrapper.js +1 -1
  16. package/dist/es2019/popup-top-layer.js +32 -21
  17. package/dist/es2019/popup.js +1 -1
  18. package/dist/es2019/use-appearance.js +11 -3
  19. package/dist/esm/compositional/popup-content-top-layer.js +30 -18
  20. package/dist/esm/compositional/popup.js +1 -1
  21. package/dist/esm/compositional/trigger-ref-object-context.js +2 -2
  22. package/dist/esm/internal/get-popup-axis-sizes.js +36 -0
  23. package/dist/esm/popper-wrapper.js +1 -1
  24. package/dist/esm/popup-top-layer.js +28 -20
  25. package/dist/esm/popup.js +1 -1
  26. package/dist/esm/use-appearance.js +11 -3
  27. package/dist/types/compositional/trigger-ref-object-context.d.ts +2 -2
  28. package/dist/types/internal/get-popup-axis-sizes.d.ts +25 -0
  29. package/dist/types/types.d.ts +30 -0
  30. package/package.json +9 -4
  31. package/dist/cjs/compositional/popup-content-top-layer.compiled.css +0 -2
  32. package/dist/cjs/popup-top-layer.compiled.css +0 -2
  33. package/dist/es2019/compositional/popup-content-top-layer.compiled.css +0 -2
  34. package/dist/es2019/popup-top-layer.compiled.css +0 -2
  35. package/dist/esm/compositional/popup-content-top-layer.compiled.css +0 -2
  36. package/dist/esm/popup-top-layer.compiled.css +0 -2
@@ -6,8 +6,8 @@ import { createContext } from 'react';
6
6
  * for the top-layer path. Unlike `TriggerRefContext` (which provides
7
7
  * `HTMLElement | null` as React state and causes a re-render when the trigger
8
8
  * mounts), this context provides a ref object whose identity is stable across
9
- * renders — allowing `useAnchorPosition` to receive a stable `anchorRef`
10
- * without needing to create a new ref wrapper on every `triggerRef` state change.
9
+ * renders — allowing `useAnchoredPopover` to receive a stable anchor ref without
10
+ * needing to create a new ref wrapper on every `triggerRef` state change.
11
11
  */
12
12
  export const TriggerRefObjectContext = /*#__PURE__*/createContext({
13
13
  current: null
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Maps the legacy `shouldFitContainer` / `shouldFitViewport` pair onto
3
+ * `useAnchoredPopover`'s per-axis sizes. Shared by the standard and the
4
+ * compositional adapter so the two cannot drift.
5
+ *
6
+ * Both props can be set together while `inlineSize` takes one value, so
7
+ * `shouldFitContainer` wins the inline axis, being the more specific request.
8
+ * Fitting then applies to the block axis only, and still turns the
9
+ * placement-axis floor on, so a cramped popup flips rather than letterboxing.
10
+ *
11
+ * Known cost on a `left-*` / `right-*` placement: the anchor floor is unclamped
12
+ * so it can drive the flip, and a min beats a max, so a trigger wider than the
13
+ * viewport is floored past the viewport cap. Not new, and not reconciled - see
14
+ * `@atlaskit/top-layer`'s `notes/decisions/width-from-anchor-floors.md`.
15
+ */
16
+ export function getPopupAxisSizes({
17
+ shouldFitContainer,
18
+ shouldFitViewport
19
+ }) {
20
+ const blockSize = shouldFitViewport ? 'max-available' : 'content';
21
+ if (shouldFitContainer) {
22
+ return {
23
+ inlineSize: 'match-anchor',
24
+ blockSize
25
+ };
26
+ }
27
+ if (shouldFitViewport) {
28
+ return {
29
+ inlineSize: 'max-available',
30
+ blockSize
31
+ };
32
+ }
33
+ return {
34
+ inlineSize: 'content',
35
+ blockSize
36
+ };
37
+ }
@@ -1,4 +1,4 @@
1
- /* popper-wrapper.tsx generated by @compiled/babel-plugin v2.0.0 */
1
+ /* popper-wrapper.tsx generated by @compiled/babel-plugin v3.0.1 */
2
2
  import _extends from "@babel/runtime/helpers/extends";
3
3
  import "./popper-wrapper.compiled.css";
4
4
  import * as React from 'react';
@@ -1,6 +1,5 @@
1
- /* popup-top-layer.tsx generated by @compiled/babel-plugin v2.0.0 */
1
+ /* popup-top-layer.tsx generated by @compiled/babel-plugin v3.0.1 */
2
2
  import _extends from "@babel/runtime/helpers/extends";
3
- import "./popup-top-layer.compiled.css";
4
3
  import * as React from 'react';
5
4
  import { ax, ix } from "@compiled/react/runtime";
6
5
  import { Fragment, memo, useCallback, useEffect, useMemo, useRef } from 'react';
@@ -10,15 +9,10 @@ import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map/index';
10
9
  import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event';
11
10
  import { Popover } from '@atlaskit/top-layer/popover/popover';
12
11
  import { PopoverSurface } from '@atlaskit/top-layer/popover-surface';
13
- import { useAnchorPosition } from '@atlaskit/top-layer/use-anchor-position';
12
+ import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
14
13
  import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
15
- import { useWidthFromAnchor } from '@atlaskit/top-layer/use-width-from-anchor';
14
+ import { getPopupAxisSizes } from './internal/get-popup-axis-sizes';
16
15
  import { useRoleProps } from './internal/top-layer-bridge';
17
- const contentOverflowStyles = {
18
- fitViewport: "_1reo1wug _18m91wug",
19
- default: ""
20
- };
21
-
22
16
  // Top-layer positioning is handled by CSS Anchor Positioning, not inline styles.
23
17
  const EMPTY_STYLE = {};
24
18
 
@@ -81,8 +75,14 @@ export const PopupTopLayer = /*#__PURE__*/memo(function PopupTopLayer({
81
75
  // top-layer: focus trapping is role-based. shouldDisableFocusLock is a no-op.
82
76
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
83
77
  shouldDisableFocusLock: _shouldDisableFocusLock,
84
- // top-layer: shouldFitViewport is handled via overflow on content wrapper.
85
- shouldFitViewport,
78
+ // top-layer: maps onto `'max-available'`, capping the popup to the space
79
+ // between the trigger and the viewport edge. `PopoverSurface` already owns
80
+ // `overflow: auto`, so the capped surface scrolls.
81
+ //
82
+ // Keep the explicit `false`: `undefined` previously reached an
83
+ // `isEnabled = true` default and silently enabled fitting for every popup
84
+ // that omitted the prop.
85
+ shouldFitViewport = false,
86
86
  // top-layer: appearance is accepted but UNSAFE_modal-below-sm is not yet implemented.
87
87
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
88
88
  appearance: _appearance
@@ -159,17 +159,15 @@ export const PopupTopLayer = /*#__PURE__*/memo(function PopupTopLayer({
159
159
  legacy: placement,
160
160
  offset: offsetProp
161
161
  }), [placement, offsetProp]);
162
- useAnchorPosition({
162
+ useAnchoredPopover({
163
163
  anchorRef: triggerRef,
164
164
  popoverRef,
165
165
  placement: topLayerPlacement,
166
- isOpen
167
- });
168
- useWidthFromAnchor({
169
- mode: shouldFitContainer ? 'match-anchor' : 'none',
170
- popoverRef,
171
- anchorRef: triggerRef,
172
- isOpen
166
+ isOpen,
167
+ ...getPopupAxisSizes({
168
+ shouldFitContainer,
169
+ shouldFitViewport
170
+ })
173
171
  });
174
172
 
175
173
  // onClose bridge.
@@ -250,7 +248,20 @@ export const PopupTopLayer = /*#__PURE__*/memo(function PopupTopLayer({
250
248
  "data-testid": testId,
251
249
  tabIndex: autoFocus ? -1 : undefined,
252
250
  xcss: xcss
253
- }, content(contentProps)) : /*#__PURE__*/React.createElement(PopoverSurface, null, /*#__PURE__*/React.createElement("div", {
254
- className: ax([contentOverflowStyles[shouldFitViewport ? 'fitViewport' : 'default']])
251
+ // Forwarded because several in-tree containers key their own
252
+ // `overflow: auto` branch off it.
253
+ ,
254
+ shouldFitViewport: shouldFitViewport
255
+ }, content(contentProps)) :
256
+ /*#__PURE__*/
257
+ // `PopoverSurface` owns `overflow: auto` and the `box-shadow` on the
258
+ // same element, so it is the scroll container. The wrapper exists only
259
+ // to carry the consumer's `xcss`: `PopoverSurface` exposes no
260
+ // `className` or `xcss` by design, so `xcss` lands on a CHILD of the
261
+ // surface. `width` works there; surface-level declarations apply one
262
+ // level in. Same shape as `compositional/popup-content-top-layer.tsx`.
263
+ React.createElement(PopoverSurface, null, /*#__PURE__*/React.createElement("div", {
264
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
265
+ className: xcss
255
266
  }, content(contentProps)))));
256
267
  });
@@ -1,4 +1,4 @@
1
- /* popup.tsx generated by @compiled/babel-plugin v2.0.0 */
1
+ /* popup.tsx generated by @compiled/babel-plugin v3.0.1 */
2
2
  /* eslint-disable @repo/internal/react/require-jsdoc */
3
3
  import "./popup.compiled.css";
4
4
  import * as React from 'react';
@@ -1,4 +1,5 @@
1
1
  import { useState } from 'react';
2
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
2
3
  import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/compiled';
3
4
 
4
5
  /**
@@ -13,11 +14,18 @@ export function usePopupAppearance({
13
14
  appearance: _appearance,
14
15
  shouldRenderToParent: _shouldRenderToParent
15
16
  }) {
16
- const mq = useMediaQuery('below.sm', e => {
17
+ const canBecomeModal = _appearance === 'UNSAFE_modal-below-sm';
18
+
19
+ /**
20
+ * This gate removes unnecessary state changes across the below-sm boundary
21
+ * The state change is only needed if the popup can become a modal - and this is maintained
22
+ */
23
+ const shouldUseMediaQuery = !fg('platform_dst_popup_media_query_perf_fix') || canBecomeModal;
24
+ const mq = useMediaQuery('below.sm', shouldUseMediaQuery ? e => {
17
25
  setIsSmallViewport(!!e.matches);
18
- });
26
+ } : undefined);
19
27
  const [isSmallViewport, setIsSmallViewport] = useState(!!(mq !== null && mq !== void 0 && mq.matches));
20
- const appearance = _appearance === 'UNSAFE_modal-below-sm' && isSmallViewport ? 'UNSAFE_modal-below-sm' : 'default';
28
+ const appearance = canBecomeModal && isSmallViewport ? 'UNSAFE_modal-below-sm' : 'default';
21
29
  const shouldRenderToParent = _shouldRenderToParent && appearance === 'default';
22
30
  return {
23
31
  appearance,
@@ -1,19 +1,20 @@
1
- /* popup-content-top-layer.tsx generated by @compiled/babel-plugin v2.0.0 */
1
+ /* popup-content-top-layer.tsx generated by @compiled/babel-plugin v3.0.1 */
2
2
  import _extends from "@babel/runtime/helpers/extends";
3
- import "./popup-content-top-layer.compiled.css";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
4
  import * as React from 'react';
5
+ import { ax, ix } from "@compiled/react/runtime";
6
+ 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; }
7
+ 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; }
5
8
  import { useCallback, useContext, useEffect, useMemo, useRef } from 'react';
6
- import { ax, ix } from '@compiled/react/runtime';
7
9
  import noop from '@atlaskit/ds-lib/noop';
8
10
  import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map/index';
9
11
  import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event';
10
12
  import { Popover } from '@atlaskit/top-layer/popover/popover';
11
13
  import { PopoverSurface } from '@atlaskit/top-layer/popover-surface';
12
- import { useAnchorPosition } from '@atlaskit/top-layer/use-anchor-position';
13
- import { useWidthFromAnchor } from '@atlaskit/top-layer/use-width-from-anchor';
14
+ import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
15
+ import { getPopupAxisSizes } from '../internal/get-popup-axis-sizes';
14
16
  import { useRoleProps } from '../internal/top-layer-bridge';
15
17
  import { TriggerRefObjectContext } from './trigger-ref-object-context';
16
- var overflowAutoStyles = null;
17
18
 
18
19
  // Top-layer positioning is handled by CSS Anchor Positioning, not inline styles.
19
20
  var EMPTY_STYLE = {};
@@ -38,8 +39,10 @@ export function PopupContentTopLayer(_ref) {
38
39
  PopupContainer = _ref.popupComponent,
39
40
  _ref$autoFocus = _ref.autoFocus,
40
41
  autoFocus = _ref$autoFocus === void 0 ? true : _ref$autoFocus,
41
- shouldFitContainer = _ref.shouldFitContainer,
42
- shouldFitViewport = _ref.shouldFitViewport,
42
+ _ref$shouldFitContain = _ref.shouldFitContainer,
43
+ shouldFitContainer = _ref$shouldFitContain === void 0 ? false : _ref$shouldFitContain,
44
+ _ref$shouldFitViewpor = _ref.shouldFitViewport,
45
+ shouldFitViewport = _ref$shouldFitViewpor === void 0 ? false : _ref$shouldFitViewpor,
43
46
  role = _ref.role,
44
47
  label = _ref.label,
45
48
  titleId = _ref.titleId,
@@ -159,18 +162,15 @@ export function PopupContentTopLayer(_ref) {
159
162
 
160
163
  // `isOpen` is included so the anchor positioning effect re-runs when
161
164
  // the Popover host element is unmounted/remounted across open cycles.
162
- useAnchorPosition({
165
+ useAnchoredPopover(_objectSpread({
163
166
  anchorRef: anchorRef,
164
167
  popoverRef: popoverRef,
165
168
  placement: topLayerPlacement,
166
169
  isOpen: isOpen
167
- });
168
- useWidthFromAnchor({
169
- mode: shouldFitContainer ? 'match-anchor' : 'none',
170
- popoverRef: popoverRef,
171
- anchorRef: anchorRef,
172
- isOpen: isOpen
173
- });
170
+ }, getPopupAxisSizes({
171
+ shouldFitContainer: shouldFitContainer,
172
+ shouldFitViewport: shouldFitViewport
173
+ })));
174
174
 
175
175
  // Narrow to ForwardRefExoticComponent so JSX accepts the ref prop.
176
176
  // All popupComponent implementations use forwardRef per the PopupComponentProps contract.
@@ -190,8 +190,20 @@ export function PopupContentTopLayer(_ref) {
190
190
  "data-testid": testId,
191
191
  tabIndex: autoFocus ? -1 : undefined,
192
192
  xcss: xcss
193
- }, children(contentProps)) : /*#__PURE__*/React.createElement(PopoverSurface, null, /*#__PURE__*/React.createElement("div", {
193
+ // Forwarded because several in-tree containers key their own
194
+ // `overflow: auto` branch off it.
195
+ ,
196
+ shouldFitViewport: shouldFitViewport
197
+ }, children(contentProps)) :
198
+ /*#__PURE__*/
199
+ // `PopoverSurface` owns `overflow: auto` and the `box-shadow` on the
200
+ // same element, so it is the scroll container. The wrapper exists only
201
+ // to carry the consumer's `xcss`: `PopoverSurface` exposes no
202
+ // `className` or `xcss` by design, so `xcss` lands on a CHILD of the
203
+ // surface. `width` works there; surface-level declarations apply one
204
+ // level in. Same shape as `../popup-top-layer.tsx`.
205
+ React.createElement(PopoverSurface, null, /*#__PURE__*/React.createElement("div", {
194
206
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
195
- className: ax([shouldFitViewport && "_1reo1wug _18m91wug", ax([xcss])])
207
+ className: xcss
196
208
  }, children(contentProps))));
197
209
  }
@@ -43,7 +43,7 @@ export var Popup = function Popup(_ref) {
43
43
  // When the top-layer flag is on, we maintain a stable RefObject for the
44
44
  // trigger element, provided through TriggerRefObjectContext. Unlike the
45
45
  // state-based triggerRef (which causes a re-render when the trigger mounts),
46
- // this ref has a stable identity so useAnchorPosition's useLayoutEffect dep
46
+ // this ref has a stable identity so useAnchoredPopover's useLayoutEffect dep
47
47
  // array never changes — the effect runs once on mount when the trigger element
48
48
  // is already populated. PopupTrigger sets this ref directly instead of calling
49
49
  // the state setter, avoiding an unnecessary re-render.
@@ -6,8 +6,8 @@ import { createContext } from 'react';
6
6
  * for the top-layer path. Unlike `TriggerRefContext` (which provides
7
7
  * `HTMLElement | null` as React state and causes a re-render when the trigger
8
8
  * mounts), this context provides a ref object whose identity is stable across
9
- * renders — allowing `useAnchorPosition` to receive a stable `anchorRef`
10
- * without needing to create a new ref wrapper on every `triggerRef` state change.
9
+ * renders — allowing `useAnchoredPopover` to receive a stable anchor ref without
10
+ * needing to create a new ref wrapper on every `triggerRef` state change.
11
11
  */
12
12
  export var TriggerRefObjectContext = /*#__PURE__*/createContext({
13
13
  current: null
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Maps the legacy `shouldFitContainer` / `shouldFitViewport` pair onto
3
+ * `useAnchoredPopover`'s per-axis sizes. Shared by the standard and the
4
+ * compositional adapter so the two cannot drift.
5
+ *
6
+ * Both props can be set together while `inlineSize` takes one value, so
7
+ * `shouldFitContainer` wins the inline axis, being the more specific request.
8
+ * Fitting then applies to the block axis only, and still turns the
9
+ * placement-axis floor on, so a cramped popup flips rather than letterboxing.
10
+ *
11
+ * Known cost on a `left-*` / `right-*` placement: the anchor floor is unclamped
12
+ * so it can drive the flip, and a min beats a max, so a trigger wider than the
13
+ * viewport is floored past the viewport cap. Not new, and not reconciled - see
14
+ * `@atlaskit/top-layer`'s `notes/decisions/width-from-anchor-floors.md`.
15
+ */
16
+ export function getPopupAxisSizes(_ref) {
17
+ var shouldFitContainer = _ref.shouldFitContainer,
18
+ shouldFitViewport = _ref.shouldFitViewport;
19
+ var blockSize = shouldFitViewport ? 'max-available' : 'content';
20
+ if (shouldFitContainer) {
21
+ return {
22
+ inlineSize: 'match-anchor',
23
+ blockSize: blockSize
24
+ };
25
+ }
26
+ if (shouldFitViewport) {
27
+ return {
28
+ inlineSize: 'max-available',
29
+ blockSize: blockSize
30
+ };
31
+ }
32
+ return {
33
+ inlineSize: 'content',
34
+ blockSize: blockSize
35
+ };
36
+ }
@@ -1,4 +1,4 @@
1
- /* popper-wrapper.tsx generated by @compiled/babel-plugin v2.0.0 */
1
+ /* popper-wrapper.tsx generated by @compiled/babel-plugin v3.0.1 */
2
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
3
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
4
4
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
@@ -1,8 +1,10 @@
1
- /* popup-top-layer.tsx generated by @compiled/babel-plugin v2.0.0 */
1
+ /* popup-top-layer.tsx generated by @compiled/babel-plugin v3.0.1 */
2
2
  import _extends from "@babel/runtime/helpers/extends";
3
- import "./popup-top-layer.compiled.css";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
4
  import * as React from 'react';
5
5
  import { ax, ix } from "@compiled/react/runtime";
6
+ 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; }
7
+ 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; }
6
8
  import { Fragment, memo, useCallback, useEffect, useMemo, useRef } from 'react';
7
9
  import noop from '@atlaskit/ds-lib/noop';
8
10
  import { getAriaForTrigger } from '@atlaskit/top-layer/get-aria-for-trigger';
@@ -10,15 +12,10 @@ import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map/index';
10
12
  import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event';
11
13
  import { Popover } from '@atlaskit/top-layer/popover/popover';
12
14
  import { PopoverSurface } from '@atlaskit/top-layer/popover-surface';
13
- import { useAnchorPosition } from '@atlaskit/top-layer/use-anchor-position';
15
+ import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
14
16
  import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
15
- import { useWidthFromAnchor } from '@atlaskit/top-layer/use-width-from-anchor';
17
+ import { getPopupAxisSizes } from './internal/get-popup-axis-sizes';
16
18
  import { useRoleProps } from './internal/top-layer-bridge';
17
- var contentOverflowStyles = {
18
- fitViewport: "_1reo1wug _18m91wug",
19
- default: ""
20
- };
21
-
22
19
  // Top-layer positioning is handled by CSS Anchor Positioning, not inline styles.
23
20
  var EMPTY_STYLE = {};
24
21
 
@@ -65,7 +62,8 @@ export var PopupTopLayer = /*#__PURE__*/memo(function PopupTopLayer(_ref) {
65
62
  _rootBoundary = _ref.rootBoundary,
66
63
  _shouldUseCaptureOnOutsideClick = _ref.shouldUseCaptureOnOutsideClick,
67
64
  _shouldDisableFocusLock = _ref.shouldDisableFocusLock,
68
- shouldFitViewport = _ref.shouldFitViewport,
65
+ _ref$shouldFitViewpor = _ref.shouldFitViewport,
66
+ shouldFitViewport = _ref$shouldFitViewpor === void 0 ? false : _ref$shouldFitViewpor,
69
67
  _appearance = _ref.appearance;
70
68
  var triggerRef = useRef(null);
71
69
  var popoverRef = useRef(null);
@@ -140,18 +138,15 @@ export var PopupTopLayer = /*#__PURE__*/memo(function PopupTopLayer(_ref) {
140
138
  offset: offsetProp
141
139
  });
142
140
  }, [placement, offsetProp]);
143
- useAnchorPosition({
141
+ useAnchoredPopover(_objectSpread({
144
142
  anchorRef: triggerRef,
145
143
  popoverRef: popoverRef,
146
144
  placement: topLayerPlacement,
147
145
  isOpen: isOpen
148
- });
149
- useWidthFromAnchor({
150
- mode: shouldFitContainer ? 'match-anchor' : 'none',
151
- popoverRef: popoverRef,
152
- anchorRef: triggerRef,
153
- isOpen: isOpen
154
- });
146
+ }, getPopupAxisSizes({
147
+ shouldFitContainer: shouldFitContainer,
148
+ shouldFitViewport: shouldFitViewport
149
+ })));
155
150
 
156
151
  // onClose bridge.
157
152
  // Translates top-layer's { reason: TPopoverCloseReason } into legacy
@@ -232,7 +227,20 @@ export var PopupTopLayer = /*#__PURE__*/memo(function PopupTopLayer(_ref) {
232
227
  "data-testid": testId,
233
228
  tabIndex: autoFocus ? -1 : undefined,
234
229
  xcss: xcss
235
- }, content(contentProps)) : /*#__PURE__*/React.createElement(PopoverSurface, null, /*#__PURE__*/React.createElement("div", {
236
- className: ax([contentOverflowStyles[shouldFitViewport ? 'fitViewport' : 'default']])
230
+ // Forwarded because several in-tree containers key their own
231
+ // `overflow: auto` branch off it.
232
+ ,
233
+ shouldFitViewport: shouldFitViewport
234
+ }, content(contentProps)) :
235
+ /*#__PURE__*/
236
+ // `PopoverSurface` owns `overflow: auto` and the `box-shadow` on the
237
+ // same element, so it is the scroll container. The wrapper exists only
238
+ // to carry the consumer's `xcss`: `PopoverSurface` exposes no
239
+ // `className` or `xcss` by design, so `xcss` lands on a CHILD of the
240
+ // surface. `width` works there; surface-level declarations apply one
241
+ // level in. Same shape as `compositional/popup-content-top-layer.tsx`.
242
+ React.createElement(PopoverSurface, null, /*#__PURE__*/React.createElement("div", {
243
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
244
+ className: xcss
237
245
  }, content(contentProps)))));
238
246
  });
package/dist/esm/popup.js CHANGED
@@ -1,4 +1,4 @@
1
- /* popup.tsx generated by @compiled/babel-plugin v2.0.0 */
1
+ /* popup.tsx generated by @compiled/babel-plugin v3.0.1 */
2
2
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
3
  import "./popup.compiled.css";
4
4
  import * as React from 'react';
@@ -1,5 +1,6 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
2
  import { useState } from 'react';
3
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
3
4
  import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/compiled';
4
5
 
5
6
  /**
@@ -13,14 +14,21 @@ import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/comp
13
14
  export function usePopupAppearance(_ref) {
14
15
  var _appearance = _ref.appearance,
15
16
  _shouldRenderToParent = _ref.shouldRenderToParent;
16
- var mq = useMediaQuery('below.sm', function (e) {
17
+ var canBecomeModal = _appearance === 'UNSAFE_modal-below-sm';
18
+
19
+ /**
20
+ * This gate removes unnecessary state changes across the below-sm boundary
21
+ * The state change is only needed if the popup can become a modal - and this is maintained
22
+ */
23
+ var shouldUseMediaQuery = !fg('platform_dst_popup_media_query_perf_fix') || canBecomeModal;
24
+ var mq = useMediaQuery('below.sm', shouldUseMediaQuery ? function (e) {
17
25
  setIsSmallViewport(!!e.matches);
18
- });
26
+ } : undefined);
19
27
  var _useState = useState(!!(mq !== null && mq !== void 0 && mq.matches)),
20
28
  _useState2 = _slicedToArray(_useState, 2),
21
29
  isSmallViewport = _useState2[0],
22
30
  setIsSmallViewport = _useState2[1];
23
- var appearance = _appearance === 'UNSAFE_modal-below-sm' && isSmallViewport ? 'UNSAFE_modal-below-sm' : 'default';
31
+ var appearance = canBecomeModal && isSmallViewport ? 'UNSAFE_modal-below-sm' : 'default';
24
32
  var shouldRenderToParent = _shouldRenderToParent && appearance === 'default';
25
33
  return {
26
34
  appearance: appearance,
@@ -4,7 +4,7 @@ import { type Context, type MutableRefObject } from 'react';
4
4
  * for the top-layer path. Unlike `TriggerRefContext` (which provides
5
5
  * `HTMLElement | null` as React state and causes a re-render when the trigger
6
6
  * mounts), this context provides a ref object whose identity is stable across
7
- * renders — allowing `useAnchorPosition` to receive a stable `anchorRef`
8
- * without needing to create a new ref wrapper on every `triggerRef` state change.
7
+ * renders — allowing `useAnchoredPopover` to receive a stable anchor ref without
8
+ * needing to create a new ref wrapper on every `triggerRef` state change.
9
9
  */
10
10
  export declare const TriggerRefObjectContext: Context<MutableRefObject<HTMLElement | null>>;
@@ -0,0 +1,25 @@
1
+ import type { TAnchoredPopoverOptions } from '@atlaskit/top-layer/use-anchored-popover';
2
+ type TPopupAxisSize = NonNullable<TAnchoredPopoverOptions['inlineSize']>;
3
+ /**
4
+ * Maps the legacy `shouldFitContainer` / `shouldFitViewport` pair onto
5
+ * `useAnchoredPopover`'s per-axis sizes. Shared by the standard and the
6
+ * compositional adapter so the two cannot drift.
7
+ *
8
+ * Both props can be set together while `inlineSize` takes one value, so
9
+ * `shouldFitContainer` wins the inline axis, being the more specific request.
10
+ * Fitting then applies to the block axis only, and still turns the
11
+ * placement-axis floor on, so a cramped popup flips rather than letterboxing.
12
+ *
13
+ * Known cost on a `left-*` / `right-*` placement: the anchor floor is unclamped
14
+ * so it can drive the flip, and a min beats a max, so a trigger wider than the
15
+ * viewport is floored past the viewport cap. Not new, and not reconciled - see
16
+ * `@atlaskit/top-layer`'s `notes/decisions/width-from-anchor-floors.md`.
17
+ */
18
+ export declare function getPopupAxisSizes({ shouldFitContainer, shouldFitViewport, }: {
19
+ shouldFitContainer: boolean;
20
+ shouldFitViewport: boolean;
21
+ }): {
22
+ inlineSize: TPopupAxisSize;
23
+ blockSize: TPopupAxisSize;
24
+ };
25
+ export {};
@@ -46,6 +46,36 @@ export interface ContentProps {
46
46
  */
47
47
  setInitialFocusRef: Dispatch<SetStateAction<HTMLElement | null>>;
48
48
  }
49
+ /**
50
+ * Props passed to a custom `popupComponent`, which renders as the popup container in
51
+ * place of the default surface.
52
+ *
53
+ * **Contract on the top-layer path (`platform-dst-top-layer`).** The container is
54
+ * the first child of a `display: flex` popover host whose `& > *` rule sets
55
+ * `flex-grow: 1`, `min-inline-size: 0` and `min-block-size: 0`. A size cap
56
+ * (`shouldFitViewport`, or the always-on viewport backstop) reaches the content only
57
+ * through that first child, so a container has to:
58
+ *
59
+ * 1. Render exactly one in-flow root. A second in-flow root becomes a second flex
60
+ * item, laid out in a row beside the first.
61
+ * 2. Keep that root in flow, not `position: absolute` or `fixed`. An out-of-flow root
62
+ * is not a flex item, so `flex-grow` and cross-axis stretch never reach it.
63
+ * 3. Give the root ITSELF a non-`visible` computed `overflow`, so it is the scroll
64
+ * container. The `min-*-size: 0` reset caps the root's box whatever its
65
+ * `overflow` is; a `visible` root's content spills out of a correctly-sized box
66
+ * instead of scrolling.
67
+ * 4. Leave the block size `auto`, so cross-axis stretch can size it.
68
+ * 5. Not pin the inline size above the cap, and not set `flex-shrink: 0`.
69
+ * 6. Put the `overflow` on the root, not on a descendant. `& > *` reaches one level.
70
+ *
71
+ * `shouldFitViewport` is forwarded on both paths, so the container can own its
72
+ * `overflow` (several in-tree containers key an `overflow: auto` branch off it).
73
+ *
74
+ * `shouldRenderToParent` is NOT forwarded on the top-layer path, by decision:
75
+ * everything renders in the top layer, so the container receives `undefined`, and a
76
+ * `(!shouldRenderToParent || shouldFitViewport)` branch reads as "fitting applies",
77
+ * which is the intended reading there.
78
+ */
49
79
  export interface PopupComponentProps {
50
80
  /**
51
81
  * Children passed through by the parent popup.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/popup",
3
- "version": "6.3.3",
3
+ "version": "6.3.5",
4
4
  "description": "A popup displays brief content in an overlay.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -40,8 +40,8 @@
40
40
  "@atlaskit/portal": "^6.4.0",
41
41
  "@atlaskit/primitives": "^22.5.0",
42
42
  "@atlaskit/react-compiler-gating": "^0.2.0",
43
- "@atlaskit/tokens": "^16.11.0",
44
- "@atlaskit/top-layer": "^4.4.0",
43
+ "@atlaskit/tokens": "^16.12.0",
44
+ "@atlaskit/top-layer": "^5.0.0",
45
45
  "@babel/runtime": "^7.0.0",
46
46
  "@compiled/react": "^1.0.2",
47
47
  "bind-event-listener": "^3.0.0",
@@ -60,11 +60,12 @@
60
60
  "@atlaskit/banner": "^15.3.0",
61
61
  "@atlaskit/button": "^25.3.0",
62
62
  "@atlaskit/code": "^19.2.0",
63
+ "@atlaskit/datetime-picker": "^18.7.0",
63
64
  "@atlaskit/docs": "^12.2.0",
64
65
  "@atlaskit/dropdown-menu": "^18.3.0",
65
66
  "@atlaskit/form": "^17.2.0",
66
67
  "@atlaskit/heading": "^7.2.0",
67
- "@atlaskit/icon": "^37.6.0",
68
+ "@atlaskit/icon": "^37.7.0",
68
69
  "@atlaskit/link": "^5.1.0",
69
70
  "@atlaskit/menu": "^10.2.0",
70
71
  "@atlaskit/modal-dialog": "^16.6.0",
@@ -78,6 +79,7 @@
78
79
  "@atlassian/ssr-tests": "workspace:^",
79
80
  "@atlassian/structured-docs-types": "workspace:^",
80
81
  "@atlassian/testing-library": "^0.11.0",
82
+ "@atlassian/workbench": "workspace:*",
81
83
  "ast-types": "^0.13.3",
82
84
  "jscodeshift": "^17.0.0",
83
85
  "raf-stub": "^2.0.1",
@@ -116,6 +118,9 @@
116
118
  },
117
119
  "platform_dst-popup-trigger-initial-focus-ref": {
118
120
  "type": "boolean"
121
+ },
122
+ "platform_dst_popup_media_query_perf_fix": {
123
+ "type": "boolean"
119
124
  }
120
125
  },
121
126
  "homepage": "https://atlassian.design/components/popup/"
@@ -1,2 +0,0 @@
1
- ._18m91wug{overflow-y:auto}
2
- ._1reo1wug{overflow-x:auto}
@@ -1,2 +0,0 @@
1
- ._18m91wug{overflow-y:auto}
2
- ._1reo1wug{overflow-x:auto}
@@ -1,2 +0,0 @@
1
- ._18m91wug{overflow-y:auto}
2
- ._1reo1wug{overflow-x:auto}
@@ -1,2 +0,0 @@
1
- ._18m91wug{overflow-y:auto}
2
- ._1reo1wug{overflow-x:auto}
@@ -1,2 +0,0 @@
1
- ._18m91wug{overflow-y:auto}
2
- ._1reo1wug{overflow-x:auto}
@@ -1,2 +0,0 @@
1
- ._18m91wug{overflow-y:auto}
2
- ._1reo1wug{overflow-x:auto}