@atlaskit/top-layer 1.0.0 → 1.0.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 +22 -0
- package/dist/cjs/internal/use-initial-focus.js +6 -0
- package/dist/cjs/popover/popover.js +27 -5
- package/dist/cjs/testing/polyfill.js +12 -0
- package/dist/es2019/internal/use-initial-focus.js +6 -0
- package/dist/es2019/popover/popover.js +27 -5
- package/dist/es2019/testing/polyfill.js +12 -0
- package/dist/esm/internal/use-initial-focus.js +6 -0
- package/dist/esm/popover/popover.js +27 -5
- package/dist/esm/testing/polyfill.js +12 -0
- package/dist/types/popover/popover.d.ts +27 -5
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @atlaskit/top-layer
|
|
2
2
|
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Patch 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
|
+
|
|
3
25
|
## 1.0.0
|
|
4
26
|
|
|
5
27
|
### Major Changes
|
|
@@ -133,6 +133,12 @@ function getInitialFocusTarget(_ref2) {
|
|
|
133
133
|
container: container
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
|
+
|
|
137
|
+
// The combobox carve-out is kept role-specific (menu / listbox) rather
|
|
138
|
+
// than hoisted. Hoisting it over-matched on dialog popups that contain
|
|
139
|
+
// a nested combobox (e.g. datetime-picker's dialog hosts a react-select),
|
|
140
|
+
// where the active combobox's `aria-controls` falsely matched the
|
|
141
|
+
// container and suppressed the dialog's own focus contract.
|
|
136
142
|
if (role === 'menu') {
|
|
137
143
|
if (isComboboxControllingPopup({
|
|
138
144
|
container: container
|
|
@@ -46,14 +46,36 @@ var styles = {
|
|
|
46
46
|
var POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree', 'grid']);
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Unopinionated top-layer primitive.
|
|
49
|
+
* Unopinionated top-layer primitive. Owns visibility and animation only;
|
|
50
50
|
* compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
|
|
51
51
|
*
|
|
52
|
-
*
|
|
53
|
-
* `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
52
|
+
* ### 🔌 Visibility
|
|
54
53
|
*
|
|
55
|
-
*
|
|
56
|
-
* `
|
|
54
|
+
* - `isOpen={true}` calls `showPopover()` (entry via `@starting-style`).
|
|
55
|
+
* - `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
56
|
+
*
|
|
57
|
+
* ### 📜 Browser dismiss is non-cancellable
|
|
58
|
+
*
|
|
59
|
+
* Per the popover spec, `beforetoggle` is cancellable on open transitions
|
|
60
|
+
* only, not on close. Consumers that need to ignore a specific dismiss
|
|
61
|
+
* (e.g. a click on a logically-associated external trigger) must reconcile
|
|
62
|
+
* inside their own `onClose` handler by calling `showPopover()` again.
|
|
63
|
+
* `Popover` does not self-heal so consumers do not pay a reconcile cost
|
|
64
|
+
* by default.
|
|
65
|
+
*
|
|
66
|
+
* - Spec: <https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute>
|
|
67
|
+
* - <https://github.com/whatwg/html/issues/8973>
|
|
68
|
+
*
|
|
69
|
+
* ### ⚠️ Open from `onClick`, not `onPointerDown`
|
|
70
|
+
*
|
|
71
|
+
* The light-dismiss algorithm captures the pointerdown target before the
|
|
72
|
+
* popover exists and dismisses on the matching pointerup if that target is
|
|
73
|
+
* not in the popover's ancestor chain. Opening during pointerdown hides
|
|
74
|
+
* the popover on the next pointerup.
|
|
75
|
+
*
|
|
76
|
+
* Legacy triggers that must open on mousedown (e.g. `@atlaskit/react-select`)
|
|
77
|
+
* should defer the open past the in-flight gesture; see
|
|
78
|
+
* `Select.openMenuAfterPointerUp`.
|
|
57
79
|
*/
|
|
58
80
|
var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Popover(_ref, ref) {
|
|
59
81
|
var children = _ref.children,
|
|
@@ -521,6 +521,18 @@ function handleDocumentKeydown(event) {
|
|
|
521
521
|
if (typeof HTMLElement !== 'undefined') {
|
|
522
522
|
var schedulePopoverToggle = createToggleScheduler();
|
|
523
523
|
|
|
524
|
+
// jsdom throws `SyntaxError` on the `:popover-open` pseudo-class. Answer
|
|
525
|
+
// it from the polyfill's `data-popover-open` source of truth and
|
|
526
|
+
// delegate every other selector to the original implementation.
|
|
527
|
+
// Spec: https://html.spec.whatwg.org/multipage/semantics-other.html#selector-popover-open
|
|
528
|
+
var originalMatches = Element.prototype.matches;
|
|
529
|
+
Element.prototype.matches = function patchedMatches(selector) {
|
|
530
|
+
if (selector === ':popover-open') {
|
|
531
|
+
return this.hasAttribute('data-popover-open');
|
|
532
|
+
}
|
|
533
|
+
return originalMatches.call(this, selector);
|
|
534
|
+
};
|
|
535
|
+
|
|
524
536
|
// Spec: https://html.spec.whatwg.org/multipage/popover.html#dom-showpopover
|
|
525
537
|
if (!HTMLElement.prototype.showPopover) {
|
|
526
538
|
HTMLElement.prototype.showPopover = function showPopover() {
|
|
@@ -127,6 +127,12 @@ function getInitialFocusTarget({
|
|
|
127
127
|
container
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
// The combobox carve-out is kept role-specific (menu / listbox) rather
|
|
132
|
+
// than hoisted. Hoisting it over-matched on dialog popups that contain
|
|
133
|
+
// a nested combobox (e.g. datetime-picker's dialog hosts a react-select),
|
|
134
|
+
// where the active combobox's `aria-controls` falsely matched the
|
|
135
|
+
// container and suppressed the dialog's own focus contract.
|
|
130
136
|
if (role === 'menu') {
|
|
131
137
|
if (isComboboxControllingPopup({
|
|
132
138
|
container
|
|
@@ -35,14 +35,36 @@ const styles = {
|
|
|
35
35
|
const POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree', 'grid']);
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Unopinionated top-layer primitive.
|
|
38
|
+
* Unopinionated top-layer primitive. Owns visibility and animation only;
|
|
39
39
|
* compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
* `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
41
|
+
* ### 🔌 Visibility
|
|
43
42
|
*
|
|
44
|
-
*
|
|
45
|
-
* `
|
|
43
|
+
* - `isOpen={true}` calls `showPopover()` (entry via `@starting-style`).
|
|
44
|
+
* - `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
45
|
+
*
|
|
46
|
+
* ### 📜 Browser dismiss is non-cancellable
|
|
47
|
+
*
|
|
48
|
+
* Per the popover spec, `beforetoggle` is cancellable on open transitions
|
|
49
|
+
* only, not on close. Consumers that need to ignore a specific dismiss
|
|
50
|
+
* (e.g. a click on a logically-associated external trigger) must reconcile
|
|
51
|
+
* inside their own `onClose` handler by calling `showPopover()` again.
|
|
52
|
+
* `Popover` does not self-heal so consumers do not pay a reconcile cost
|
|
53
|
+
* by default.
|
|
54
|
+
*
|
|
55
|
+
* - Spec: <https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute>
|
|
56
|
+
* - <https://github.com/whatwg/html/issues/8973>
|
|
57
|
+
*
|
|
58
|
+
* ### ⚠️ Open from `onClick`, not `onPointerDown`
|
|
59
|
+
*
|
|
60
|
+
* The light-dismiss algorithm captures the pointerdown target before the
|
|
61
|
+
* popover exists and dismisses on the matching pointerup if that target is
|
|
62
|
+
* not in the popover's ancestor chain. Opening during pointerdown hides
|
|
63
|
+
* the popover on the next pointerup.
|
|
64
|
+
*
|
|
65
|
+
* Legacy triggers that must open on mousedown (e.g. `@atlaskit/react-select`)
|
|
66
|
+
* should defer the open past the in-flight gesture; see
|
|
67
|
+
* `Select.openMenuAfterPointerUp`.
|
|
46
68
|
*/
|
|
47
69
|
export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
48
70
|
children,
|
|
@@ -535,6 +535,18 @@ function handleDocumentKeydown(event) {
|
|
|
535
535
|
if (typeof HTMLElement !== 'undefined') {
|
|
536
536
|
const schedulePopoverToggle = createToggleScheduler();
|
|
537
537
|
|
|
538
|
+
// jsdom throws `SyntaxError` on the `:popover-open` pseudo-class. Answer
|
|
539
|
+
// it from the polyfill's `data-popover-open` source of truth and
|
|
540
|
+
// delegate every other selector to the original implementation.
|
|
541
|
+
// Spec: https://html.spec.whatwg.org/multipage/semantics-other.html#selector-popover-open
|
|
542
|
+
const originalMatches = Element.prototype.matches;
|
|
543
|
+
Element.prototype.matches = function patchedMatches(selector) {
|
|
544
|
+
if (selector === ':popover-open') {
|
|
545
|
+
return this.hasAttribute('data-popover-open');
|
|
546
|
+
}
|
|
547
|
+
return originalMatches.call(this, selector);
|
|
548
|
+
};
|
|
549
|
+
|
|
538
550
|
// Spec: https://html.spec.whatwg.org/multipage/popover.html#dom-showpopover
|
|
539
551
|
if (!HTMLElement.prototype.showPopover) {
|
|
540
552
|
HTMLElement.prototype.showPopover = function showPopover() {
|
|
@@ -127,6 +127,12 @@ function getInitialFocusTarget(_ref2) {
|
|
|
127
127
|
container: container
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
// The combobox carve-out is kept role-specific (menu / listbox) rather
|
|
132
|
+
// than hoisted. Hoisting it over-matched on dialog popups that contain
|
|
133
|
+
// a nested combobox (e.g. datetime-picker's dialog hosts a react-select),
|
|
134
|
+
// where the active combobox's `aria-controls` falsely matched the
|
|
135
|
+
// container and suppressed the dialog's own focus contract.
|
|
130
136
|
if (role === 'menu') {
|
|
131
137
|
if (isComboboxControllingPopup({
|
|
132
138
|
container: container
|
|
@@ -37,14 +37,36 @@ var styles = {
|
|
|
37
37
|
var POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree', 'grid']);
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Unopinionated top-layer primitive.
|
|
40
|
+
* Unopinionated top-layer primitive. Owns visibility and animation only;
|
|
41
41
|
* compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
* `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
43
|
+
* ### 🔌 Visibility
|
|
45
44
|
*
|
|
46
|
-
*
|
|
47
|
-
* `
|
|
45
|
+
* - `isOpen={true}` calls `showPopover()` (entry via `@starting-style`).
|
|
46
|
+
* - `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
47
|
+
*
|
|
48
|
+
* ### 📜 Browser dismiss is non-cancellable
|
|
49
|
+
*
|
|
50
|
+
* Per the popover spec, `beforetoggle` is cancellable on open transitions
|
|
51
|
+
* only, not on close. Consumers that need to ignore a specific dismiss
|
|
52
|
+
* (e.g. a click on a logically-associated external trigger) must reconcile
|
|
53
|
+
* inside their own `onClose` handler by calling `showPopover()` again.
|
|
54
|
+
* `Popover` does not self-heal so consumers do not pay a reconcile cost
|
|
55
|
+
* by default.
|
|
56
|
+
*
|
|
57
|
+
* - Spec: <https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute>
|
|
58
|
+
* - <https://github.com/whatwg/html/issues/8973>
|
|
59
|
+
*
|
|
60
|
+
* ### ⚠️ Open from `onClick`, not `onPointerDown`
|
|
61
|
+
*
|
|
62
|
+
* The light-dismiss algorithm captures the pointerdown target before the
|
|
63
|
+
* popover exists and dismisses on the matching pointerup if that target is
|
|
64
|
+
* not in the popover's ancestor chain. Opening during pointerdown hides
|
|
65
|
+
* the popover on the next pointerup.
|
|
66
|
+
*
|
|
67
|
+
* Legacy triggers that must open on mousedown (e.g. `@atlaskit/react-select`)
|
|
68
|
+
* should defer the open past the in-flight gesture; see
|
|
69
|
+
* `Select.openMenuAfterPointerUp`.
|
|
48
70
|
*/
|
|
49
71
|
export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
50
72
|
var children = _ref.children,
|
|
@@ -519,6 +519,18 @@ function handleDocumentKeydown(event) {
|
|
|
519
519
|
if (typeof HTMLElement !== 'undefined') {
|
|
520
520
|
var schedulePopoverToggle = createToggleScheduler();
|
|
521
521
|
|
|
522
|
+
// jsdom throws `SyntaxError` on the `:popover-open` pseudo-class. Answer
|
|
523
|
+
// it from the polyfill's `data-popover-open` source of truth and
|
|
524
|
+
// delegate every other selector to the original implementation.
|
|
525
|
+
// Spec: https://html.spec.whatwg.org/multipage/semantics-other.html#selector-popover-open
|
|
526
|
+
var originalMatches = Element.prototype.matches;
|
|
527
|
+
Element.prototype.matches = function patchedMatches(selector) {
|
|
528
|
+
if (selector === ':popover-open') {
|
|
529
|
+
return this.hasAttribute('data-popover-open');
|
|
530
|
+
}
|
|
531
|
+
return originalMatches.call(this, selector);
|
|
532
|
+
};
|
|
533
|
+
|
|
522
534
|
// Spec: https://html.spec.whatwg.org/multipage/popover.html#dom-showpopover
|
|
523
535
|
if (!HTMLElement.prototype.showPopover) {
|
|
524
536
|
HTMLElement.prototype.showPopover = function showPopover() {
|
|
@@ -5,13 +5,35 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { type TPopoverForwardedProps } from './types';
|
|
7
7
|
/**
|
|
8
|
-
* Unopinionated top-layer primitive.
|
|
8
|
+
* Unopinionated top-layer primitive. Owns visibility and animation only;
|
|
9
9
|
* compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
11
|
+
* ### 🔌 Visibility
|
|
13
12
|
*
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
13
|
+
* - `isOpen={true}` calls `showPopover()` (entry via `@starting-style`).
|
|
14
|
+
* - `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
15
|
+
*
|
|
16
|
+
* ### 📜 Browser dismiss is non-cancellable
|
|
17
|
+
*
|
|
18
|
+
* Per the popover spec, `beforetoggle` is cancellable on open transitions
|
|
19
|
+
* only, not on close. Consumers that need to ignore a specific dismiss
|
|
20
|
+
* (e.g. a click on a logically-associated external trigger) must reconcile
|
|
21
|
+
* inside their own `onClose` handler by calling `showPopover()` again.
|
|
22
|
+
* `Popover` does not self-heal so consumers do not pay a reconcile cost
|
|
23
|
+
* by default.
|
|
24
|
+
*
|
|
25
|
+
* - Spec: <https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute>
|
|
26
|
+
* - <https://github.com/whatwg/html/issues/8973>
|
|
27
|
+
*
|
|
28
|
+
* ### ⚠️ Open from `onClick`, not `onPointerDown`
|
|
29
|
+
*
|
|
30
|
+
* The light-dismiss algorithm captures the pointerdown target before the
|
|
31
|
+
* popover exists and dismisses on the matching pointerup if that target is
|
|
32
|
+
* not in the popover's ancestor chain. Opening during pointerdown hides
|
|
33
|
+
* the popover on the next pointerup.
|
|
34
|
+
*
|
|
35
|
+
* Legacy triggers that must open on mousedown (e.g. `@atlaskit/react-select`)
|
|
36
|
+
* should defer the open past the in-flight gesture; see
|
|
37
|
+
* `Select.openMenuAfterPointerUp`.
|
|
16
38
|
*/
|
|
17
39
|
export declare const Popover: React.ForwardRefExoticComponent<TPopoverForwardedProps & React.RefAttributes<HTMLDivElement>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/top-layer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.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",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@af/integration-testing": "workspace:^",
|
|
53
53
|
"@af/visual-regression": "workspace:^",
|
|
54
|
-
"@atlaskit/button": "^24.
|
|
54
|
+
"@atlaskit/button": "^24.1.0",
|
|
55
55
|
"@atlaskit/heading": "^6.0.0",
|
|
56
56
|
"@atlaskit/lozenge": "^14.0.0",
|
|
57
57
|
"@atlaskit/primitives": "^20.0.0",
|