@atlaskit/top-layer 1.0.0 → 1.0.2

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,36 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`ee28cf33718b0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ee28cf33718b0) -
8
+ Add @atlassian/react-compiler-gating as a runtime dependency to enable React Compiler platform
9
+ gating.
10
+ - Updated dependencies
11
+
12
+ ## 1.0.1
13
+
14
+ ### Patch Changes
15
+
16
+ - [`642a4ddbce9f4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/642a4ddbce9f4) -
17
+ [ux] The Select menu is being migrated to the browser top layer. The new behaviour is gated behind
18
+ the `platform-dst-top-layer` feature flag and ships dark; there are no public API changes for
19
+ `@atlaskit/react-select` or `@atlaskit/select`.
20
+
21
+ Internal-only improvements to support consumer migrations:
22
+ - Polyfilled the `:popover-open` CSS pseudo-class in the jsdom test polyfill so consumers can
23
+ assert on popover open state in unit tests without a browser.
24
+ - Removed a defensive `try/catch` around `element.matches()` in `Popover` that was only needed to
25
+ work around the missing pseudo-class.
26
+ - Clarified, via an inline comment in `use-initial-focus`, why the combobox carve-out is kept
27
+ role-specific (menu / listbox) rather than hoisted above all role checks.
28
+ - Fixed a unit test for `PopupSelect` top-layer trigger click that incorrectly called `failGate`
29
+ in `afterEach`, which conflicted with the auto-reset behaviour of
30
+ `@atlassian/feature-flags-test-utils/mock-gates` and caused the suite to fail.
31
+
32
+ No public API or runtime behaviour changes for existing consumers.
33
+
3
34
  ## 1.0.0
4
35
 
5
36
  ### 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. Manages visibility and animation only;
49
+ * Unopinionated top-layer primitive. Owns visibility and animation only;
50
50
  * compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
51
51
  *
52
- * `isOpen={true}` calls `showPopover()` (entry via `@starting-style`);
53
- * `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
52
+ * ### 🔌 Visibility
54
53
  *
55
- * In `mode="auto"`, the browser can light-dismiss (Escape, click outside).
56
- * `onClose` fires; the consumer must then set `isOpen` to `false`.
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. Manages visibility and animation only;
38
+ * Unopinionated top-layer primitive. Owns visibility and animation only;
39
39
  * compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
40
40
  *
41
- * `isOpen={true}` calls `showPopover()` (entry via `@starting-style`);
42
- * `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
41
+ * ### 🔌 Visibility
43
42
  *
44
- * In `mode="auto"`, the browser can light-dismiss (Escape, click outside).
45
- * `onClose` fires; the consumer must then set `isOpen` to `false`.
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. Manages visibility and animation only;
40
+ * Unopinionated top-layer primitive. Owns visibility and animation only;
41
41
  * compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
42
42
  *
43
- * `isOpen={true}` calls `showPopover()` (entry via `@starting-style`);
44
- * `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
43
+ * ### 🔌 Visibility
45
44
  *
46
- * In `mode="auto"`, the browser can light-dismiss (Escape, click outside).
47
- * `onClose` fires; the consumer must then set `isOpen` to `false`.
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. Manages visibility and animation only;
8
+ * Unopinionated top-layer primitive. Owns visibility and animation only;
9
9
  * compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
10
10
  *
11
- * `isOpen={true}` calls `showPopover()` (entry via `@starting-style`);
12
- * `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
11
+ * ### 🔌 Visibility
13
12
  *
14
- * In `mode="auto"`, the browser can light-dismiss (Escape, click outside).
15
- * `onClose` fires; the consumer must then set `isOpen` to `false`.
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.0",
3
+ "version": "1.0.2",
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",
@@ -38,7 +38,8 @@
38
38
  "@atlaskit/css": "^1.0.0",
39
39
  "@atlaskit/ds-lib": "^8.0.0",
40
40
  "@atlaskit/layering": "^4.0.0",
41
- "@atlaskit/tokens": "^14.0.0",
41
+ "@atlaskit/tokens": "^15.0.0",
42
+ "@atlassian/react-compiler-gating": "^0.2.0",
42
43
  "@babel/runtime": "^7.0.0",
43
44
  "@compiled/react": "^0.20.0",
44
45
  "bind-event-listener": "^3.0.0",
@@ -51,13 +52,12 @@
51
52
  "devDependencies": {
52
53
  "@af/integration-testing": "workspace:^",
53
54
  "@af/visual-regression": "workspace:^",
54
- "@atlaskit/button": "^24.0.0",
55
+ "@atlaskit/button": "^24.1.0",
55
56
  "@atlaskit/heading": "^6.0.0",
56
57
  "@atlaskit/lozenge": "^14.0.0",
57
58
  "@atlaskit/primitives": "^20.0.0",
58
59
  "@atlaskit/ssr": "workspace:^",
59
60
  "@atlaskit/textfield": "^9.0.0",
60
- "@atlassian/react-compiler-gating": "workspace:^",
61
61
  "@atlassian/ssr-tests": "workspace:^",
62
62
  "@atlassian/testing-library": "^0.6.0",
63
63
  "@testing-library/jest-dom": "^6.4.5",