@atlaskit/react-select 4.0.2 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @atlaskit/react-select
2
2
 
3
+ ## 4.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`642a4ddbce9f4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/642a4ddbce9f4) -
8
+ [ux] The Select menu is being migrated to the browser top layer. The new behaviour is gated behind
9
+ the `platform-dst-top-layer` feature flag and ships dark; there are no public API changes for
10
+ `@atlaskit/react-select` or `@atlaskit/select`.
11
+
12
+ Internal-only improvements to support consumer migrations:
13
+ - Polyfilled the `:popover-open` CSS pseudo-class in the jsdom test polyfill so consumers can
14
+ assert on popover open state in unit tests without a browser.
15
+ - Removed a defensive `try/catch` around `element.matches()` in `Popover` that was only needed to
16
+ work around the missing pseudo-class.
17
+ - Clarified, via an inline comment in `use-initial-focus`, why the combobox carve-out is kept
18
+ role-specific (menu / listbox) rather than hoisted above all role checks.
19
+ - Fixed a unit test for `PopupSelect` top-layer trigger click that incorrectly called `failGate`
20
+ in `afterEach`, which conflicted with the auto-reset behaviour of
21
+ `@atlassian/feature-flags-test-utils/mock-gates` and caused the suite to fail.
22
+
23
+ No public API or runtime behaviour changes for existing consumers.
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies
28
+
3
29
  ## 4.0.2
4
30
 
5
31
  ### Patch Changes
@@ -9,6 +9,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
10
  var _react = require("react");
11
11
  var _noop = _interopRequireDefault(require("@atlaskit/ds-lib/noop"));
12
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
12
13
  var _portalPlacementContext = require("../internal/portal-placement-context");
13
14
  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; }
14
15
  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) { (0, _defineProperty2.default)(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; }
@@ -269,6 +270,12 @@ var MenuPlacer = function MenuPlacer(props) {
269
270
  // The minimum height of the control
270
271
  var controlHeight = 38;
271
272
  (0, _react.useLayoutEffect)(function () {
273
+ // When the menu is hosted in the browser top layer, positioning, flipping
274
+ // and viewport-fit are all handled by `@atlaskit/top-layer`. The placer
275
+ // becomes a pass-through that only forwards `maxMenuHeight` as a cap.
276
+ if ((0, _platformFeatureFlags.fg)('platform-dst-top-layer')) {
277
+ return;
278
+ }
272
279
  var menuEl = ref.current;
273
280
  if (!menuEl) {
274
281
  return;
@@ -0,0 +1 @@
1
+ ._ofie1496{max-block-size:100dvh}
@@ -0,0 +1,151 @@
1
+ /* menu-portal-top-layer.tsx generated by @compiled/babel-plugin v0.39.1 */
2
+ "use strict";
3
+
4
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
5
+ var _typeof = require("@babel/runtime/helpers/typeof");
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ exports.MenuPortalTopLayer = MenuPortalTopLayer;
10
+ require("./menu-portal-top-layer.compiled.css");
11
+ var _react = _interopRequireWildcard(require("react"));
12
+ var React = _react;
13
+ var _runtime = require("@compiled/react/runtime");
14
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
15
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
16
+ var _react2 = require("@compiled/react");
17
+ var _openLayerObserver = require("@atlaskit/layering/experimental/open-layer-observer");
18
+ var _popover = require("@atlaskit/top-layer/popover");
19
+ var _useAnchorPosition = require("@atlaskit/top-layer/use-anchor-position");
20
+ var _useWidthFromAnchor = require("@atlaskit/top-layer/use-width-from-anchor");
21
+ var _getStyleProps2 = require("../get-style-props");
22
+ var _menuPortalCloseContext = require("../internal/menu-portal-close-context");
23
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
24
+ 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; }
25
+ 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) { (0, _defineProperty2.default)(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; }
26
+ // `'auto'` falls through to `'end'`; top-layer's `position-try-fallbacks` flips it if needed.
27
+ function reactSelectEdgeToTopLayerEdge(menuPlacement) {
28
+ return menuPlacement === 'top' ? 'start' : 'end';
29
+ }
30
+ var menuPortalStyles = {
31
+ root: "_ofie1496"
32
+ };
33
+
34
+ /**
35
+ * Top-layer host for react-select's menu. Hands positioning, flip, and width
36
+ * to `@atlaskit/top-layer`; ignores `appendTo` / `menuPortalTarget` /
37
+ * `menuPosition`. The browser-dismiss handler is supplied internally by
38
+ * `Select` via `MenuPortalCloseContext`.
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * <MenuPortalTopLayer controlElement={el} menuPlacement="bottom">
43
+ * <Menu />
44
+ * </MenuPortalTopLayer>
45
+ * ```
46
+ */
47
+ function MenuPortalTopLayer(props) {
48
+ var children = props.children,
49
+ controlElement = props.controlElement,
50
+ innerProps = props.innerProps,
51
+ menuPlacement = props.menuPlacement,
52
+ menuPosition = props.menuPosition,
53
+ xcss = props.xcss;
54
+ // Select's "close the menu" callback, distinct from `Popover.onClose`.
55
+ var closeSelect = (0, _react.useContext)(_menuPortalCloseContext.MenuPortalCloseContext);
56
+ var popoverRef = (0, _react.useRef)(null);
57
+
58
+ // Top-layer hooks need a RefObject; in-render mutation keeps it in sync
59
+ // with the prop without an effect. The hooks re-read `.current` from
60
+ // `isOpen`-keyed layout effects, so a stable ref identity is fine.
61
+ var anchorRef = (0, _react.useRef)(null);
62
+ anchorRef.current = controlElement;
63
+
64
+ // `controlElement` is null on initial mount / SSR until `Select` mirrors
65
+ // its ref into state. While null, every hook below no-ops to avoid DOM
66
+ // reads or registering an unpositioned popover.
67
+ var isAnchored = controlElement !== null;
68
+
69
+ // `gap: 0` matches the legacy MenuPortal (no trigger-to-menu gap; the
70
+ // menu root already declares its own `marginBlockStart`). Without this
71
+ // override `useAnchorPosition`'s default 8px gap would diverge visually
72
+ // from the legacy path.
73
+ (0, _useAnchorPosition.useAnchorPosition)({
74
+ anchorRef: anchorRef,
75
+ popoverRef: popoverRef,
76
+ placement: {
77
+ axis: 'block',
78
+ edge: reactSelectEdgeToTopLayerEdge(menuPlacement),
79
+ offset: {
80
+ gap: 0
81
+ }
82
+ },
83
+ isOpen: isAnchored
84
+ });
85
+ (0, _useWidthFromAnchor.useWidthFromAnchor)({
86
+ anchorRef: anchorRef,
87
+ popoverRef: popoverRef,
88
+ mode: 'match-anchor',
89
+ isOpen: isAnchored
90
+ });
91
+ var handlePopoverClose = (0, _react.useCallback)(function () {
92
+ if (closeSelect) {
93
+ closeSelect();
94
+ }
95
+ }, [closeSelect]);
96
+
97
+ // Explicit observer registration: the outer Popover is intentionally
98
+ // roleless (see Popover comment below), so Popover cannot auto-register
99
+ // from its role. This lets `closeLayers()` (Modal / Drawer) dismiss us.
100
+ (0, _openLayerObserver.useNotifyOpenLayerObserver)({
101
+ type: 'popup',
102
+ isOpen: isAnchored,
103
+ onClose: handlePopoverClose
104
+ });
105
+
106
+ // Top-layer owns positioning; zero offset/rect preserves the consumer
107
+ // styles call shape.
108
+ var _getStyleProps = (0, _getStyleProps2.getStyleProps)(_objectSpread(_objectSpread({}, props), {}, {
109
+ offset: 0,
110
+ position: menuPosition,
111
+ rect: {
112
+ left: 0,
113
+ width: 0
114
+ }
115
+ }), 'menuPortal', {
116
+ 'menu-portal': true
117
+ }),
118
+ className = _getStyleProps.className;
119
+
120
+ // Popover stays mounted and is driven by `isOpen` so its layout-effect
121
+ // teardown (`hidePopover`, observer cleanup, position-hook style reset)
122
+ // runs against a live element. Conditional render would skip that path.
123
+ //
124
+ // `mode="manual"` opts out of native light-dismiss: react-select already
125
+ // owns outside-click and Escape via its own handlers, and the combobox
126
+ // trigger lives in a separate DOM subtree that the spec algorithm cannot
127
+ // see. Matches the pattern in `@atlaskit/datetime-picker`'s MenuTopLayer.
128
+ //
129
+ // The Popover host is intentionally roleless: the inner `MenuList`
130
+ // keeps `role="listbox"` and the id referenced by `aria-controls`.
131
+ // Putting the role on the outer host caused Playwright `toBeVisible`
132
+ // and some SR hit-testing to treat it as hidden (zero bounding rect
133
+ // while `styles.root` opts out of UA `[popover]` positioning).
134
+ //
135
+ // TODO: add open / close animation. Select unmounts MenuPortalTopLayer
136
+ // the moment `menuIsOpen` flips false, so Popover's `animate` exit
137
+ // transition never gets a frame. Needs keeping the portal mounted
138
+ // through the exit (`onExitFinish`) on the Select side.
139
+ return /*#__PURE__*/React.createElement(_popover.Popover, {
140
+ ref: popoverRef,
141
+ mode: "manual",
142
+ isOpen: isAnchored,
143
+ onClose: handlePopoverClose
144
+ }, /*#__PURE__*/React.createElement("div", (0, _extends2.default)({
145
+ // `className` carries consumer `styles.menuPortal({...})` output,
146
+ // `xcss` carries caller compiled atomic classes, and `-MenuPortal`
147
+ // is a legacy selector hook kept for parity with MenuPortalLegacy.
148
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop, @atlaskit/ui-styling-standard/local-cx-xcss, @compiled/local-cx-xcss, @typescript-eslint/no-explicit-any
149
+ className: (0, _runtime.ax)([menuPortalStyles.root, (0, _react2.cx)(className, xcss, '-MenuPortal')])
150
+ }, innerProps), children));
151
+ }
@@ -17,8 +17,10 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
17
17
  var _react2 = require("@compiled/react");
18
18
  var _dom = require("@floating-ui/dom");
19
19
  var _reactDom = require("react-dom");
20
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
20
21
  var _getStyleProps2 = require("../get-style-props");
21
22
  var _portalPlacementContext = require("../internal/portal-placement-context");
23
+ var _menuPortalTopLayer = require("./menu-portal-top-layer");
22
24
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
23
25
  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; }
24
26
  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) { (0, _defineProperty2.default)(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; }
@@ -40,7 +42,7 @@ var menuPortalStyles = {
40
42
  root: "_1pbykb7n _1e02a1vk _kqswcp1v _152t1nmo _1bsb1qxj"
41
43
  };
42
44
  // eslint-disable-next-line @repo/internal/react/require-jsdoc
43
- var MenuPortal = exports.MenuPortal = function MenuPortal(props) {
45
+ function MenuPortalLegacy(props) {
44
46
  var appendTo = props.appendTo,
45
47
  children = props.children,
46
48
  controlElement = props.controlElement,
@@ -99,7 +101,10 @@ var MenuPortal = exports.MenuPortal = function MenuPortal(props) {
99
101
  runAutoUpdate();
100
102
  }, [runAutoUpdate]);
101
103
 
102
- // bail early if required elements aren't present
104
+ // Legacy quirk: `computedPosition` is null until the layout effect runs,
105
+ // so the first render returns null even with `defaultMenuIsOpen` set.
106
+ // Synchronous observers (VR snapshots) see a one-frame "closed" state.
107
+ // Left as-is; the top-layer path supersedes this and positions declaratively.
103
108
  if (!appendTo && menuPosition !== 'fixed' || !computedPosition) {
104
109
  return null;
105
110
  }
@@ -129,4 +134,19 @@ var MenuPortal = exports.MenuPortal = function MenuPortal(props) {
129
134
  return /*#__PURE__*/React.createElement(_portalPlacementContext.PortalPlacementContext.Provider, {
130
135
  value: portalPlacementContext
131
136
  }, appendTo ? /*#__PURE__*/(0, _reactDom.createPortal)(menuWrapper, appendTo) : menuWrapper);
137
+ }
138
+
139
+ /**
140
+ * Public-facing `MenuPortal` component. Routes between the legacy
141
+ * `createPortal`-based implementation and the top-layer-based
142
+ * `MenuPortalTopLayer` based on the `platform-dst-top-layer` feature flag.
143
+ */
144
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
145
+ var MenuPortal = exports.MenuPortal = function MenuPortal(props) {
146
+ if ((0, _platformFeatureFlags.fg)('platform-dst-top-layer')) {
147
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
148
+ return /*#__PURE__*/React.createElement(_menuPortalTopLayer.MenuPortalTopLayer, props);
149
+ }
150
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
151
+ return /*#__PURE__*/React.createElement(MenuPortalLegacy, props);
132
152
  };
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MenuPortalCloseContext = void 0;
7
+ var _react = require("react");
8
+ /**
9
+ * Internal handoff from `Select` to `MenuPortalTopLayer` for the top-layer
10
+ * dismiss signal. Kept off `MenuPortalProps` to avoid widening the public
11
+ * subpath export at `@atlaskit/react-select/menu-portal`.
12
+ */
13
+ var MenuPortalCloseContext = exports.MenuPortalCloseContext = /*#__PURE__*/(0, _react.createContext)(undefined);