@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.
- package/CHANGELOG.md +22 -0
- package/__tests__/playwright/fit-viewport.spec.tsx +225 -0
- package/dist/cjs/compositional/popup-content-top-layer.js +30 -19
- package/dist/cjs/compositional/popup.js +1 -1
- package/dist/cjs/compositional/trigger-ref-object-context.js +2 -2
- package/dist/cjs/internal/get-popup-axis-sizes.js +42 -0
- package/dist/cjs/popper-wrapper.js +1 -1
- package/dist/cjs/popup-top-layer.js +28 -20
- package/dist/cjs/popup.js +1 -1
- package/dist/cjs/use-appearance.js +11 -3
- package/dist/es2019/compositional/popup-content-top-layer.js +27 -18
- package/dist/es2019/compositional/popup.js +1 -1
- package/dist/es2019/compositional/trigger-ref-object-context.js +2 -2
- package/dist/es2019/internal/get-popup-axis-sizes.js +37 -0
- package/dist/es2019/popper-wrapper.js +1 -1
- package/dist/es2019/popup-top-layer.js +32 -21
- package/dist/es2019/popup.js +1 -1
- package/dist/es2019/use-appearance.js +11 -3
- package/dist/esm/compositional/popup-content-top-layer.js +30 -18
- package/dist/esm/compositional/popup.js +1 -1
- package/dist/esm/compositional/trigger-ref-object-context.js +2 -2
- package/dist/esm/internal/get-popup-axis-sizes.js +36 -0
- package/dist/esm/popper-wrapper.js +1 -1
- package/dist/esm/popup-top-layer.js +28 -20
- package/dist/esm/popup.js +1 -1
- package/dist/esm/use-appearance.js +11 -3
- package/dist/types/compositional/trigger-ref-object-context.d.ts +2 -2
- package/dist/types/internal/get-popup-axis-sizes.d.ts +25 -0
- package/dist/types/types.d.ts +30 -0
- package/package.json +9 -4
- package/dist/cjs/compositional/popup-content-top-layer.compiled.css +0 -2
- package/dist/cjs/popup-top-layer.compiled.css +0 -2
- package/dist/es2019/compositional/popup-content-top-layer.compiled.css +0 -2
- package/dist/es2019/popup-top-layer.compiled.css +0 -2
- package/dist/esm/compositional/popup-content-top-layer.compiled.css +0 -2
- 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 `
|
|
10
|
-
*
|
|
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,6 +1,5 @@
|
|
|
1
|
-
/* popup-top-layer.tsx generated by @compiled/babel-plugin
|
|
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 {
|
|
12
|
+
import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
|
|
14
13
|
import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
|
|
15
|
-
import {
|
|
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:
|
|
85
|
-
|
|
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
|
-
|
|
162
|
+
useAnchoredPopover({
|
|
163
163
|
anchorRef: triggerRef,
|
|
164
164
|
popoverRef,
|
|
165
165
|
placement: topLayerPlacement,
|
|
166
|
-
isOpen
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
254
|
-
|
|
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
|
});
|
package/dist/es2019/popup.js
CHANGED
|
@@ -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
|
|
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 =
|
|
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
|
|
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 "
|
|
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 {
|
|
13
|
-
import {
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
165
|
+
useAnchoredPopover(_objectSpread({
|
|
163
166
|
anchorRef: anchorRef,
|
|
164
167
|
popoverRef: popoverRef,
|
|
165
168
|
placement: topLayerPlacement,
|
|
166
169
|
isOpen: isOpen
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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 `
|
|
10
|
-
*
|
|
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
|
|
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
|
|
1
|
+
/* popup-top-layer.tsx generated by @compiled/babel-plugin v3.0.1 */
|
|
2
2
|
import _extends from "@babel/runtime/helpers/extends";
|
|
3
|
-
import "
|
|
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 {
|
|
15
|
+
import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
|
|
14
16
|
import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
|
|
15
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
141
|
+
useAnchoredPopover(_objectSpread({
|
|
144
142
|
anchorRef: triggerRef,
|
|
145
143
|
popoverRef: popoverRef,
|
|
146
144
|
placement: topLayerPlacement,
|
|
147
145
|
isOpen: isOpen
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
236
|
-
|
|
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,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
|
|
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 =
|
|
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 `
|
|
8
|
-
*
|
|
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 {};
|
package/dist/types/types.d.ts
CHANGED
|
@@ -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
|
+
"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.
|
|
44
|
-
"@atlaskit/top-layer": "^
|
|
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.
|
|
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/"
|