@atlaskit/top-layer 6.1.1 → 6.2.1

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,20 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 6.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`26ee4b1f57a30`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/26ee4b1f57a30) -
8
+ Fix nested-menu detection and read arrow-navigation focus from the container's document.
9
+
10
+ ## 6.2.0
11
+
12
+ ### Minor Changes
13
+
14
+ - [`fd59fcdb03cf1`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fd59fcdb03cf1) -
15
+ `Popover` registers with the open layer observer only when it has an `onClose`, and manual popover
16
+ props now accept `onClose`.
17
+
3
18
  ## 6.1.1
4
19
 
5
20
  ### Patch Changes
@@ -179,7 +179,8 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
179
179
 
180
180
  // Register with open layer observer so `closeLayers()` and open-count
181
181
  // subscriptions work. Only popup-like roles register as `popup`; passive
182
- // roles (tooltip, status, etc.) leave `type` undefined.
182
+ // roles (tooltip, status, etc.) leave `type` undefined. Without `onClose`
183
+ // the layer cannot be closed, so it does not register.
183
184
  var handleObserverClose = (0, _react.useCallback)(function () {
184
185
  var _onCloseRef$current;
185
186
  (_onCloseRef$current = onCloseRef.current) === null || _onCloseRef$current === void 0 || _onCloseRef$current.call(onCloseRef, {
@@ -188,7 +189,7 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
188
189
  }, []);
189
190
  (0, _useNotifyOpenLayerObserver.useNotifyOpenLayerObserver)({
190
191
  type: role && POPUP_ROLES.has(role) ? 'popup' : undefined,
191
- isOpen: isOpen,
192
+ isOpen: isOpen && Boolean(onClose),
192
193
  onClose: handleObserverClose
193
194
  });
194
195
 
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useArrowNavigation = useArrowNavigation;
7
7
  var _react = require("react");
8
8
  var _bindEventListener = require("bind-event-listener");
9
- var _browserApis = require("@atlaskit/browser-apis");
10
9
  var _keycodes = require("@atlaskit/ds-lib/keycodes");
11
10
  var _getFirstFocusable2 = require("../focus/get-first-focusable");
12
11
  var _getLastFocusable2 = require("../focus/get-last-focusable");
@@ -73,7 +72,6 @@ function useArrowNavigation(_ref) {
73
72
  isEnabled = _ref$isEnabled === void 0 ? true : _ref$isEnabled,
74
73
  filter = _ref.filter;
75
74
  var handleKeyDown = (0, _react.useCallback)(function (event) {
76
- var _getDocument;
77
75
  var container = containerRef.current;
78
76
  if (!container) {
79
77
  return;
@@ -84,7 +82,7 @@ function useArrowNavigation(_ref) {
84
82
  // [role="menu"] must be this container (not a nested sub-menu).
85
83
  // When no filter is provided, fall back to the closest-menu check
86
84
  // if the container has role="menu".
87
- var focused = (_getDocument = (0, _browserApis.getDocument)()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement;
85
+ var focused = container.ownerDocument.activeElement;
88
86
  if (focused instanceof HTMLElement) {
89
87
  if (filter) {
90
88
  if (!filter(focused, container)) {
@@ -161,7 +159,7 @@ function useArrowNavigation(_ref) {
161
159
  // Only close if this container is inside another role="menu"
162
160
  // (i.e. it is a submenu, not the top-level menu).
163
161
  // Walk up from the parent to avoid matching the container itself.
164
- var isNested = ((_container$parentElem = container.parentElement) === null || _container$parentElem === void 0 ? void 0 : _container$parentElem.closest(menuScope)) !== null;
162
+ var isNested = Boolean((_container$parentElem = container.parentElement) === null || _container$parentElem === void 0 ? void 0 : _container$parentElem.closest(menuScope));
165
163
  if (isNested) {
166
164
  event.preventDefault();
167
165
  onNestedClose();
@@ -173,7 +173,8 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
173
173
 
174
174
  // Register with open layer observer so `closeLayers()` and open-count
175
175
  // subscriptions work. Only popup-like roles register as `popup`; passive
176
- // roles (tooltip, status, etc.) leave `type` undefined.
176
+ // roles (tooltip, status, etc.) leave `type` undefined. Without `onClose`
177
+ // the layer cannot be closed, so it does not register.
177
178
  const handleObserverClose = useCallback(() => {
178
179
  var _onCloseRef$current;
179
180
  (_onCloseRef$current = onCloseRef.current) === null || _onCloseRef$current === void 0 ? void 0 : _onCloseRef$current.call(onCloseRef, {
@@ -182,7 +183,7 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
182
183
  }, []);
183
184
  useNotifyOpenLayerObserver({
184
185
  type: role && POPUP_ROLES.has(role) ? 'popup' : undefined,
185
- isOpen,
186
+ isOpen: isOpen && Boolean(onClose),
186
187
  onClose: handleObserverClose
187
188
  });
188
189
 
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useEffect } from 'react';
2
2
  import { bind } from 'bind-event-listener';
3
- import { getDocument } from '@atlaskit/browser-apis';
4
3
  import { KEY_DOWN, KEY_END, KEY_HOME, KEY_TAB, KEY_UP } from '@atlaskit/ds-lib/keycodes';
5
4
  import { getFirstFocusable } from '../focus/get-first-focusable';
6
5
  import { getLastFocusable } from '../focus/get-last-focusable';
@@ -67,7 +66,6 @@ export function useArrowNavigation({
67
66
  filter
68
67
  }) {
69
68
  const handleKeyDown = useCallback(event => {
70
- var _getDocument;
71
69
  const container = containerRef.current;
72
70
  if (!container) {
73
71
  return;
@@ -78,7 +76,7 @@ export function useArrowNavigation({
78
76
  // [role="menu"] must be this container (not a nested sub-menu).
79
77
  // When no filter is provided, fall back to the closest-menu check
80
78
  // if the container has role="menu".
81
- const focused = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement;
79
+ const focused = container.ownerDocument.activeElement;
82
80
  if (focused instanceof HTMLElement) {
83
81
  if (filter) {
84
82
  if (!filter(focused, container)) {
@@ -155,7 +153,7 @@ export function useArrowNavigation({
155
153
  // Only close if this container is inside another role="menu"
156
154
  // (i.e. it is a submenu, not the top-level menu).
157
155
  // Walk up from the parent to avoid matching the container itself.
158
- const isNested = ((_container$parentElem = container.parentElement) === null || _container$parentElem === void 0 ? void 0 : _container$parentElem.closest(menuScope)) !== null;
156
+ const isNested = Boolean((_container$parentElem = container.parentElement) === null || _container$parentElem === void 0 ? void 0 : _container$parentElem.closest(menuScope));
159
157
  if (isNested) {
160
158
  event.preventDefault();
161
159
  onNestedClose();
@@ -170,7 +170,8 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref2, ref) {
170
170
 
171
171
  // Register with open layer observer so `closeLayers()` and open-count
172
172
  // subscriptions work. Only popup-like roles register as `popup`; passive
173
- // roles (tooltip, status, etc.) leave `type` undefined.
173
+ // roles (tooltip, status, etc.) leave `type` undefined. Without `onClose`
174
+ // the layer cannot be closed, so it does not register.
174
175
  var handleObserverClose = useCallback(function () {
175
176
  var _onCloseRef$current;
176
177
  (_onCloseRef$current = onCloseRef.current) === null || _onCloseRef$current === void 0 || _onCloseRef$current.call(onCloseRef, {
@@ -179,7 +180,7 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref2, ref) {
179
180
  }, []);
180
181
  useNotifyOpenLayerObserver({
181
182
  type: role && POPUP_ROLES.has(role) ? 'popup' : undefined,
182
- isOpen: isOpen,
183
+ isOpen: isOpen && Boolean(onClose),
183
184
  onClose: handleObserverClose
184
185
  });
185
186
 
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useEffect } from 'react';
2
2
  import { bind } from 'bind-event-listener';
3
- import { getDocument } from '@atlaskit/browser-apis';
4
3
  import { KEY_DOWN, KEY_END, KEY_HOME, KEY_TAB, KEY_UP } from '@atlaskit/ds-lib/keycodes';
5
4
  import { getFirstFocusable } from '../focus/get-first-focusable';
6
5
  import { getLastFocusable } from '../focus/get-last-focusable';
@@ -67,7 +66,6 @@ export function useArrowNavigation(_ref) {
67
66
  isEnabled = _ref$isEnabled === void 0 ? true : _ref$isEnabled,
68
67
  filter = _ref.filter;
69
68
  var handleKeyDown = useCallback(function (event) {
70
- var _getDocument;
71
69
  var container = containerRef.current;
72
70
  if (!container) {
73
71
  return;
@@ -78,7 +76,7 @@ export function useArrowNavigation(_ref) {
78
76
  // [role="menu"] must be this container (not a nested sub-menu).
79
77
  // When no filter is provided, fall back to the closest-menu check
80
78
  // if the container has role="menu".
81
- var focused = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement;
79
+ var focused = container.ownerDocument.activeElement;
82
80
  if (focused instanceof HTMLElement) {
83
81
  if (filter) {
84
82
  if (!filter(focused, container)) {
@@ -155,7 +153,7 @@ export function useArrowNavigation(_ref) {
155
153
  // Only close if this container is inside another role="menu"
156
154
  // (i.e. it is a submenu, not the top-level menu).
157
155
  // Walk up from the parent to avoid matching the container itself.
158
- var isNested = ((_container$parentElem = container.parentElement) === null || _container$parentElem === void 0 ? void 0 : _container$parentElem.closest(menuScope)) !== null;
156
+ var isNested = Boolean((_container$parentElem = container.parentElement) === null || _container$parentElem === void 0 ? void 0 : _container$parentElem.closest(menuScope));
159
157
  if (isNested) {
160
158
  event.preventDefault();
161
159
  onNestedClose();
@@ -21,6 +21,12 @@ export type TPopoverCloseReason = 'escape' | 'light-dismiss' | 'programmatic';
21
21
  */
22
22
  export type TPopoverForwardedProps = TPopoverBaseProps & {
23
23
  mode?: 'auto' | 'hint' | 'manual';
24
+ /**
25
+ * Called when the popover asks to close. See `TPopoverProps` for each `reason`.
26
+ *
27
+ * Also opts the popover into the open layer observer: only a popover with
28
+ * `onClose` registers, so only it can be closed by `closeLayers()`.
29
+ */
24
30
  onClose?: (args: {
25
31
  reason: TPopoverCloseReason;
26
32
  }) => void;
@@ -165,14 +171,29 @@ export type TPopoverProps = TPopoverBaseProps & TAriaRoleRequired & ({
165
171
  * controlled intent after native dismissal. If `isOpen` remains `true`,
166
172
  * the Popover remains natively closed until the prop changes.
167
173
  *
168
- * The `reason` field indicates how the dismiss occurred:
174
+ * The `reason` field indicates how the close was requested:
169
175
  * - `'escape'`: the user pressed the Escape key.
170
176
  * - `'light-dismiss'`: the user clicked outside (or another auto-dismiss).
177
+ * - `'programmatic'`: the open layer observer's `closeLayers()` asked
178
+ * every open layer to close (for example, the side navigation toggle).
179
+ * The popover stays open until the consumer sets `isOpen` to `false`.
171
180
  */
172
181
  onClose: (args: {
173
182
  reason: TPopoverCloseReason;
174
183
  }) => void;
175
184
  } | {
176
185
  mode: 'manual';
177
- onClose?: never;
186
+ /**
187
+ * Enables programmatic close through the open layer observer. When
188
+ * provided, the popover registers as an open layer, and `closeLayers()`
189
+ * calls this with `reason: 'programmatic'`. Set `isOpen` to `false` in
190
+ * response. Without it, the popover does not register, so `closeLayers()`
191
+ * cannot close it and it is not counted as an open layer.
192
+ *
193
+ * Manual popovers have no light dismiss, so this is the only reason
194
+ * they receive.
195
+ */
196
+ onClose?: (args: {
197
+ reason: TPopoverCloseReason;
198
+ }) => void;
178
199
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/top-layer",
3
- "version": "6.1.1",
3
+ "version": "6.2.1",
4
4
  "description": "Low-level layering primitives based on popover and dialog",
5
5
  "homepage": "https://atlassian.design/components/top-layer",
6
6
  "repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",