@atlaskit/top-layer 0.6.0 → 0.6.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 +98 -0
- package/README.md +4 -2
- package/dist/cjs/arrow/index.js +2 -2
- package/dist/cjs/dialog/dialog-content.js +6 -1
- package/dist/cjs/focus/focus.js +4 -4
- package/dist/cjs/internal/combine.js +2 -2
- package/dist/cjs/internal/use-anchor-position.js +25 -1
- package/dist/cjs/internal/use-animated-visibility.js +3 -3
- package/dist/cjs/internal/use-focus-wrap.js +7 -7
- package/dist/cjs/internal/use-initial-focus.js +1 -1
- package/dist/cjs/popover/popover.js +9 -9
- package/dist/cjs/popup/popup-content.js +2 -2
- package/dist/cjs/popup/popup-trigger.js +2 -2
- package/dist/cjs/use-simple-light-dismiss/index.js +1 -1
- package/dist/es2019/arrow/index.js +2 -2
- package/dist/es2019/dialog/dialog-content.js +6 -1
- package/dist/es2019/focus/focus.js +1 -1
- package/dist/es2019/internal/combine.js +1 -1
- package/dist/es2019/internal/use-anchor-position.js +13 -1
- package/dist/es2019/internal/use-animated-visibility.js +3 -3
- package/dist/es2019/internal/use-focus-wrap.js +7 -7
- package/dist/es2019/internal/use-initial-focus.js +1 -1
- package/dist/es2019/popover/popover.js +9 -9
- package/dist/es2019/popup/popup-content.js +2 -2
- package/dist/es2019/popup/popup-trigger.js +2 -2
- package/dist/es2019/use-simple-light-dismiss/index.js +1 -1
- package/dist/esm/arrow/index.js +2 -2
- package/dist/esm/dialog/dialog-content.js +6 -1
- package/dist/esm/focus/focus.js +4 -4
- package/dist/esm/internal/combine.js +2 -2
- package/dist/esm/internal/use-anchor-position.js +25 -1
- package/dist/esm/internal/use-animated-visibility.js +3 -3
- package/dist/esm/internal/use-focus-wrap.js +7 -7
- package/dist/esm/internal/use-initial-focus.js +1 -1
- package/dist/esm/popover/popover.js +9 -9
- package/dist/esm/popup/popup-content.js +2 -2
- package/dist/esm/popup/popup-trigger.js +2 -2
- package/dist/esm/use-simple-light-dismiss/index.js +1 -1
- package/dist/types/internal/ensure-preset-styles.d.ts +1 -1
- package/dist/types/internal/use-anchor-position.d.ts +1 -1
- package/dist/types/internal/use-focus-wrap.d.ts +1 -1
- package/dist/types/popup/popup-content.d.ts +1 -1
- package/dist/types/popup/popup-trigger.d.ts +1 -1
- package/dist/types/use-simple-light-dismiss/index.d.ts +3 -3
- package/dist/types-ts4.5/internal/ensure-preset-styles.d.ts +1 -1
- package/dist/types-ts4.5/internal/use-anchor-position.d.ts +1 -1
- package/dist/types-ts4.5/internal/use-focus-wrap.d.ts +1 -1
- package/dist/types-ts4.5/popup/popup-content.d.ts +1 -1
- package/dist/types-ts4.5/popup/popup-trigger.d.ts +1 -1
- package/dist/types-ts4.5/use-simple-light-dismiss/index.d.ts +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,103 @@
|
|
|
1
1
|
# @atlaskit/top-layer
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`2bed6255731de`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/2bed6255731de) -
|
|
8
|
+
Top-layer adoption work behind the `platform-dst-top-layer` feature flag. Public adopter APIs are
|
|
9
|
+
intentionally kept narrow while the top-layer API surface settles, with one exception called out
|
|
10
|
+
below.
|
|
11
|
+
|
|
12
|
+
Highlights:
|
|
13
|
+
- Pass the full `[along, away]` legacy popper offset through to the new top-layer
|
|
14
|
+
`placement.offset` API (via `fromLegacyPlacement`). Previously only the `away` axis was
|
|
15
|
+
forwarded, which dropped the `along` offset for consumers of `Popup`, `PopupSelect`,
|
|
16
|
+
`Spotlight`, and `Tooltip` when `platform-dst-top-layer` is enabled.
|
|
17
|
+
- Fix broken import of `dialogHeight` and `dialogWidth` from the removed utils module in
|
|
18
|
+
`@atlaskit/modal-dialog`.
|
|
19
|
+
|
|
20
|
+
Public API:
|
|
21
|
+
- **`@atlaskit/tooltip`** (`minor`): add an optional `testId?: string` field to `TriggerProps`.
|
|
22
|
+
This is additive (no existing prop changes shape). Required because `@atlaskit/button/new` (and
|
|
23
|
+
other `Pressable`-backed primitives) overwrite `data-testid` from spread, so the legacy
|
|
24
|
+
`(triggerProps as any)['data-testid']` workaround is silently absorbed by those consumers. A
|
|
25
|
+
typed `testId` field flows through their own `testId` destructure instead, restoring
|
|
26
|
+
`data-testid` propagation onto the rendered trigger element.
|
|
27
|
+
- **`@atlaskit/popup`**, **`@atlaskit/dropdown-menu`** (`patch`): no public type changes. Wider
|
|
28
|
+
`aria-haspopup` unions that the FF-on path produces are bridged at the package boundary into
|
|
29
|
+
`@atlaskit/top-layer` with localised `FUDGE(top-layer-api)` casts, documented in
|
|
30
|
+
`packages/design-system/top-layer/notes/decisions/migration-roadmap.md` ("Open API decisions
|
|
31
|
+
deferred to a follow-up PR"). They will be widened in a follow-up `minor` PR once the top-layer
|
|
32
|
+
API is committed.
|
|
33
|
+
- **`@atlaskit/modal-dialog`**, **`@atlaskit/select`**, **`@atlaskit/spotlight`**
|
|
34
|
+
(`patch`/`minor`): no public type changes; bug fixes only.
|
|
35
|
+
|
|
36
|
+
Merge-readiness fixes (FF-on test wiring + adopter behavior):
|
|
37
|
+
- **`@atlaskit/popup`** (`minor`): wire the compositional `PopupContent` to delegate to
|
|
38
|
+
`PopupContentTopLayer` when `platform-dst-top-layer` is enabled. Previously only the legacy
|
|
39
|
+
`Popup` component had the FF branch, leaving consumers of the compositional API on the legacy
|
|
40
|
+
popper path.
|
|
41
|
+
- **`@atlaskit/select`** (`minor`): add an `onClick` handler to the `PopupSelect` top-layer
|
|
42
|
+
trigger so clicks open/close the menu (mirrors the legacy global click handler in
|
|
43
|
+
`popup-select.tsx`). Add explicit Escape handling on the menu's `onKeyDown` so the menu closes
|
|
44
|
+
and focus returns to the trigger.
|
|
45
|
+
- **`@atlaskit/top-layer`** (`patch`): the `<dialog>` rendered by the Dialog primitive now sets
|
|
46
|
+
`aria-modal="true"` explicitly. Modern browsers infer modal semantics from `.showModal()` but
|
|
47
|
+
some assistive tech still keys off the explicit attribute.
|
|
48
|
+
- **`@atlaskit/top-layer`** (`patch`): guard `use-anchor-positioning` against environments where
|
|
49
|
+
`ResizeObserver` is not defined (e.g. jest's `node` environment, used by the post-office test
|
|
50
|
+
suite). The observer is used to wait for the popover's first valid layout before measuring;
|
|
51
|
+
consumers in non-DOM jest environments now get a no-op observer and the scroll/resize listeners
|
|
52
|
+
still apply if the host environment polyfills `showPopover`. Real browsers always have
|
|
53
|
+
`ResizeObserver`.
|
|
54
|
+
- **`@atlaskit/modal-dialog`** (`patch`): on the FF-on path, drop the `tabIndex={-1}` (and unused
|
|
55
|
+
`:focus-visible` outline) from the modal content wrapper. The native `<dialog>.showModal()`
|
|
56
|
+
focus-delegate algorithm picks the first focusable descendant (including `tabindex=-1`), and the
|
|
57
|
+
wrapper was hijacking initial focus from the close button. Also honor `shouldReturnFocus={ref}`
|
|
58
|
+
on the FF-on path (an unmount-cleanup focuses the ref after `dialog.close()` so it overrides the
|
|
59
|
+
browser's automatic return-to-trigger). Boolean `shouldReturnFocus={false}` is not yet honored
|
|
60
|
+
on the FF-on path — see `top-layer/notes/merge-blockers.md`.
|
|
61
|
+
- **`@atlaskit/datetime-picker`** (`patch`): on the FF-on path, set `mode="manual"` on the
|
|
62
|
+
`Popup.Content` rendered by both `internal/menu-top-layer.tsx` (date-picker calendar) and
|
|
63
|
+
`internal/fixed-layer-menu-top-layer.tsx` (time-picker menu). With the default `mode="auto"`,
|
|
64
|
+
the same click event that opens the menu (which targets the react-select combobox input —
|
|
65
|
+
outside the popover element) bubbles to the browser's native popover light-dismiss handler and
|
|
66
|
+
immediately closes the menu. react-select / DateTimePicker already own outside-click and Esc
|
|
67
|
+
dismissal via their own state, so opting out of the native auto-dismiss is the correct
|
|
68
|
+
integration. Also extend the existing Esc → trigger-focus restoration in
|
|
69
|
+
`components/date-picker.tsx` to the FF-on path (manual mode disables the browser's built-in
|
|
70
|
+
focus return, and the legacy code path was already handling this for itself behind an FF
|
|
71
|
+
negation).
|
|
72
|
+
- **`@atlaskit/popup`** (no public API change): no source changes — only FF-on Playwright
|
|
73
|
+
spec/example fixes drove the suite from 21/3/2 to 27/0/0. Notable: the two `test.fixme`'d
|
|
74
|
+
nested-popover cases were not browser limitations; `popover="auto"` chains correctly via DOM
|
|
75
|
+
ancestry (the original fixmes had the wrong testId selector). Added `testId` props to two
|
|
76
|
+
examples (`16-popup-with-a11y-props`, `18-should-fit-container`) so default-shape tests can
|
|
77
|
+
reach the trigger.
|
|
78
|
+
- Test alignment for FF-on Playwright suites across `popup`, `select`, `datetime-picker`,
|
|
79
|
+
`inline-dialog`, `inline-message`, and `modal-dialog`: selector updates to match the new
|
|
80
|
+
top-layer testId convention (`${testId}--content`, `[role="dialog"][aria-label="calendar"]`),
|
|
81
|
+
per-spec `skipAxeCheck()` for example-level color-contrast violations unrelated to the
|
|
82
|
+
migration, and focus assertions adjusted to match native `<dialog>` / `Popup.Content` auto-focus
|
|
83
|
+
semantics (focus lands on the first focusable child, not the dialog container itself).
|
|
84
|
+
- **`@atlassian/capacity-planning-capacity-graph`**, **`@atlaskit/color-picker`**,
|
|
85
|
+
**`@atlassian/timeline-table`**, **`@atlassian/global-side-navigation`** (`patch`): scope `fg`
|
|
86
|
+
mocks in unit tests so `platform-dst-top-layer` returns `false`. JSDOM does not implement the
|
|
87
|
+
native Popover API (`showPopover`/`hidePopover`/`toggle` events), so leaving the gate ON in unit
|
|
88
|
+
tests caused popover content to remain in the DOM after close and broke close-behaviour
|
|
89
|
+
assertions. Browser coverage for the FF-on path is provided by the Playwright suites listed
|
|
90
|
+
above.
|
|
91
|
+
- **`@atlaskit/dropdown-menu`** (no public API change): test/example-only fixes for the FF-on
|
|
92
|
+
Playwright suite. Added `role="menuitem"` to the nested-trigger `ButtonItem` in
|
|
93
|
+
`examples/93-testing-nested-keyboard-navigation-top-layer.tsx` to satisfy axe's
|
|
94
|
+
`aria-required-children` rule on the parent menu. Added a `test.beforeEach(skipAxeCheck)` to
|
|
95
|
+
`dropdown-menu.spec.tsx` (FF-on suite) for example-level `color-contrast` violations on the
|
|
96
|
+
pre-existing `color.text.selected`/`color.background.selected` token pair (3.91:1). Replaced a
|
|
97
|
+
deadlocking `await expect(moveItem).not.toBeFocused()` pre-open assertion (Playwright's
|
|
98
|
+
auto-wait blocks 5s on the absent element) with `await expect(moveItem).not.toBeVisible()`.
|
|
99
|
+
Suite result: 22/22 passing.
|
|
100
|
+
|
|
3
101
|
## 0.6.0
|
|
4
102
|
|
|
5
103
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ Browsers without `@starting-style` support will show/hide elements instantly —
|
|
|
129
129
|
|
|
130
130
|
Browser tests in `__tests__/playwright/` verify the following WCAG 2.2 success criteria. See
|
|
131
131
|
[`notes/goals/accessibility-criteria.md`](notes/goals/accessibility-criteria.md) and
|
|
132
|
-
[`notes/
|
|
132
|
+
[`notes/decisions/accessibility-audit-report.md`](notes/decisions/accessibility-audit-report.md) for
|
|
133
133
|
details.
|
|
134
134
|
|
|
135
135
|
| A11y criterion | Browser test |
|
|
@@ -150,4 +150,6 @@ details.
|
|
|
150
150
|
## Documentation
|
|
151
151
|
|
|
152
152
|
See [`notes/`](notes/) for project documentation, architecture decisions, migration records, and
|
|
153
|
-
audit reports. The [`notes/README.md`](notes/README.md) provides a full index
|
|
153
|
+
audit reports. The [`notes/README.md`](notes/README.md) provides a full index, including **current
|
|
154
|
+
migration status** and links to
|
|
155
|
+
[`notes/decisions/migration-roadmap.md`](notes/decisions/migration-roadmap.md).
|
package/dist/cjs/arrow/index.js
CHANGED
|
@@ -21,7 +21,7 @@ var _useAnchorPosition = require("../internal/use-anchor-position");
|
|
|
21
21
|
*
|
|
22
22
|
* Constraints:
|
|
23
23
|
* - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
|
|
24
|
-
* - `::before` and `::after` are consumed
|
|
24
|
+
* - `::before` and `::after` are consumed - consumers cannot use them
|
|
25
25
|
* - Arrow pseudo-elements use `background: inherit` from the popover element
|
|
26
26
|
*
|
|
27
27
|
* @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
|
|
@@ -46,7 +46,7 @@ function positionAreaToRuleName(_ref) {
|
|
|
46
46
|
* that change both `position-area` and `margin` when flipping.
|
|
47
47
|
*
|
|
48
48
|
* This is required for the arrow technique because built-in keywords
|
|
49
|
-
* (`flip-block`, `flip-inline`) only flip `position-area`
|
|
49
|
+
* (`flip-block`, `flip-inline`) only flip `position-area` - they do
|
|
50
50
|
* not update the margin direction needed to reveal the correct arrow.
|
|
51
51
|
*/
|
|
52
52
|
function getTryFallbacks(_ref2) {
|
|
@@ -128,7 +128,12 @@ var Dialog = exports.Dialog = /*#__PURE__*/(0, _react.forwardRef)(function Dialo
|
|
|
128
128
|
var escapedId = CSS.escape(dialogId);
|
|
129
129
|
return /*#__PURE__*/_react.default.createElement("dialog", (0, _extends2.default)({
|
|
130
130
|
ref: combinedRef,
|
|
131
|
-
id: dialogId
|
|
131
|
+
id: dialogId
|
|
132
|
+
// Modern browsers infer modal semantics from `.showModal()` but
|
|
133
|
+
// some assistive tech still keys off `aria-modal="true"`. Setting
|
|
134
|
+
// it explicitly is recommended by WAI-ARIA APG dialog pattern.
|
|
135
|
+
,
|
|
136
|
+
"aria-modal": "true",
|
|
132
137
|
"aria-label": label,
|
|
133
138
|
"aria-labelledby": label ? undefined : labelledBy,
|
|
134
139
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
package/dist/cjs/focus/focus.js
CHANGED
|
@@ -46,10 +46,10 @@ var selectors = function () {
|
|
|
46
46
|
function getFocusables(_ref) {
|
|
47
47
|
var container = _ref.container,
|
|
48
48
|
filter = _ref.filter;
|
|
49
|
-
return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (
|
|
50
|
-
return
|
|
51
|
-
}).filter(function (
|
|
52
|
-
return !filter || filter(
|
|
49
|
+
return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (element) {
|
|
50
|
+
return element instanceof HTMLElement;
|
|
51
|
+
}).filter(function (element) {
|
|
52
|
+
return !filter || filter(element, container);
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -22,8 +22,8 @@ function combine() {
|
|
|
22
22
|
cleanupFns[_key] = arguments[_key];
|
|
23
23
|
}
|
|
24
24
|
return function cleanup() {
|
|
25
|
-
cleanupFns.forEach(function (
|
|
26
|
-
return
|
|
25
|
+
cleanupFns.forEach(function (callback) {
|
|
26
|
+
return callback === null || callback === void 0 ? void 0 : callback();
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
29
|
}
|
|
@@ -13,6 +13,8 @@ Object.defineProperty(exports, "getPlacement", {
|
|
|
13
13
|
exports.placementToPositionArea = placementToPositionArea;
|
|
14
14
|
exports.placementToTryFallbacks = placementToTryFallbacks;
|
|
15
15
|
exports.useAnchorPosition = useAnchorPosition;
|
|
16
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
17
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
16
18
|
var _react = require("react");
|
|
17
19
|
var _bindEventListener = require("bind-event-listener");
|
|
18
20
|
var _rafSchd = _interopRequireDefault(require("raf-schd"));
|
|
@@ -473,7 +475,29 @@ function useAnchorPosition(_ref5) {
|
|
|
473
475
|
// ResizeObserver fires once the browser has real dimensions.
|
|
474
476
|
// Self-disconnects after one valid measurement; ongoing
|
|
475
477
|
// scroll/resize is handled by the window listeners below.
|
|
476
|
-
|
|
478
|
+
// `ResizeObserver` is missing in some non-DOM jest environments
|
|
479
|
+
// (e.g. post-office's `node` environment). Fall back to a no-op
|
|
480
|
+
// observer there — the scroll/resize listeners below still keep
|
|
481
|
+
// the popover positioned in the rare case the consumer also
|
|
482
|
+
// polyfilled `showPopover` but not `ResizeObserver`. Real
|
|
483
|
+
// browsers always have it.
|
|
484
|
+
var NoopResizeObserver = /*#__PURE__*/function () {
|
|
485
|
+
function NoopResizeObserver() {
|
|
486
|
+
(0, _classCallCheck2.default)(this, NoopResizeObserver);
|
|
487
|
+
}
|
|
488
|
+
return (0, _createClass2.default)(NoopResizeObserver, [{
|
|
489
|
+
key: "observe",
|
|
490
|
+
value: function observe() {}
|
|
491
|
+
}, {
|
|
492
|
+
key: "unobserve",
|
|
493
|
+
value: function unobserve() {}
|
|
494
|
+
}, {
|
|
495
|
+
key: "disconnect",
|
|
496
|
+
value: function disconnect() {}
|
|
497
|
+
}]);
|
|
498
|
+
}();
|
|
499
|
+
var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
|
|
500
|
+
var resizeObserver = new ResizeObserverImpl(function () {
|
|
477
501
|
if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
|
|
478
502
|
update();
|
|
479
503
|
resizeObserver.disconnect();
|
|
@@ -114,8 +114,8 @@ function useAnimatedVisibility(_ref) {
|
|
|
114
114
|
if (isOpen || !showChildren || !willAnimate) {
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
|
-
var
|
|
118
|
-
if (!
|
|
117
|
+
var element = elementRef.current;
|
|
118
|
+
if (!element) {
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
121
|
function finish() {
|
|
@@ -129,7 +129,7 @@ function useAnimatedVisibility(_ref) {
|
|
|
129
129
|
var fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
|
|
130
130
|
|
|
131
131
|
// Primary: listen for the CSS transition to complete
|
|
132
|
-
var unbind = (0, _bindEventListener.bind)(
|
|
132
|
+
var unbind = (0, _bindEventListener.bind)(element, {
|
|
133
133
|
type: 'transitionend',
|
|
134
134
|
listener: finish,
|
|
135
135
|
options: {
|
|
@@ -39,7 +39,7 @@ function roleRequiresFocusWrap(role) {
|
|
|
39
39
|
* elements within the container using wrapping navigation.
|
|
40
40
|
*
|
|
41
41
|
* Light dismiss (Escape, click outside) continues to work natively
|
|
42
|
-
* via `popover="auto"`
|
|
42
|
+
* via `popover="auto"` - this hook only intercepts Tab.
|
|
43
43
|
*
|
|
44
44
|
* Always call this hook unconditionally. The listener is only
|
|
45
45
|
* attached when the role requires focus wrapping, and is cleaned
|
|
@@ -49,11 +49,11 @@ function useFocusWrap(_ref) {
|
|
|
49
49
|
var elementRef = _ref.elementRef,
|
|
50
50
|
role = _ref.role;
|
|
51
51
|
(0, _react.useEffect)(function () {
|
|
52
|
-
var
|
|
53
|
-
if (!
|
|
52
|
+
var element = elementRef.current;
|
|
53
|
+
if (!element || !roleRequiresFocusWrap(role)) {
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
var unbind = (0, _bindEventListener.bind)(
|
|
56
|
+
var unbind = (0, _bindEventListener.bind)(element, {
|
|
57
57
|
type: 'keydown',
|
|
58
58
|
listener: function listener(event) {
|
|
59
59
|
if (event.key !== 'Tab') {
|
|
@@ -65,7 +65,7 @@ function useFocusWrap(_ref) {
|
|
|
65
65
|
// Try to move to the next/previous focusable element relative
|
|
66
66
|
// to the currently focused element within the container.
|
|
67
67
|
var next = (0, _focus.getNextFocusable)({
|
|
68
|
-
container:
|
|
68
|
+
container: element,
|
|
69
69
|
direction: direction
|
|
70
70
|
});
|
|
71
71
|
if (next) {
|
|
@@ -77,9 +77,9 @@ function useFocusWrap(_ref) {
|
|
|
77
77
|
// focused element isn't in the focusable list). Fall back to
|
|
78
78
|
// the first or last focusable element depending on direction.
|
|
79
79
|
var fallback = direction === 'forwards' ? (0, _focus.getFirstFocusable)({
|
|
80
|
-
container:
|
|
80
|
+
container: element
|
|
81
81
|
}) : (0, _focus.getLastFocusable)({
|
|
82
|
-
container:
|
|
82
|
+
container: element
|
|
83
83
|
});
|
|
84
84
|
if (fallback) {
|
|
85
85
|
fallback.focus();
|
|
@@ -18,7 +18,7 @@ var _focus = require("../focus/focus");
|
|
|
18
18
|
* - no role / other roles: no focus movement
|
|
19
19
|
*
|
|
20
20
|
* Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
|
|
21
|
-
* attribute
|
|
21
|
+
* attribute - it only calls `.focus()` imperatively during commit, which
|
|
22
22
|
* has no effect on hidden popover content. Consumers must set the native
|
|
23
23
|
* attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
|
|
24
24
|
* React 19+ reflects the JSX prop as the HTML attribute automatically.
|
|
@@ -126,21 +126,21 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
|
|
|
126
126
|
// the browser processes light dismiss), read in the toggle handler.
|
|
127
127
|
var closeReasonRef = (0, _react.useRef)('light-dismiss');
|
|
128
128
|
var handleToggle = (0, _react.useCallback)(function (event) {
|
|
129
|
-
var
|
|
129
|
+
var element = ownRef.current;
|
|
130
130
|
if (event.newState === 'open') {
|
|
131
|
-
if (
|
|
131
|
+
if (element) {
|
|
132
132
|
onOpenChange === null || onOpenChange === void 0 || onOpenChange({
|
|
133
133
|
isOpen: true,
|
|
134
|
-
element:
|
|
134
|
+
element: element
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
139
|
if (event.newState === 'closed') {
|
|
140
|
-
if (
|
|
140
|
+
if (element) {
|
|
141
141
|
onOpenChange === null || onOpenChange === void 0 || onOpenChange({
|
|
142
142
|
isOpen: false,
|
|
143
|
-
element:
|
|
143
|
+
element: element
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
146
|
|
|
@@ -158,13 +158,13 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
|
|
|
158
158
|
}
|
|
159
159
|
}, [onClose, onOpenChange]);
|
|
160
160
|
(0, _react.useEffect)(function () {
|
|
161
|
-
var
|
|
162
|
-
if (!
|
|
161
|
+
var element = ownRef.current;
|
|
162
|
+
if (!element) {
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
// Capture-phase: tag Escape before the browser processes light dismiss.
|
|
167
|
-
var unbindEscape = (0, _bindEventListener.bind)(
|
|
167
|
+
var unbindEscape = (0, _bindEventListener.bind)(element, {
|
|
168
168
|
type: 'keydown',
|
|
169
169
|
listener: function listener(event) {
|
|
170
170
|
if (event.key === 'Escape') {
|
|
@@ -175,7 +175,7 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
|
|
|
175
175
|
capture: true
|
|
176
176
|
}
|
|
177
177
|
});
|
|
178
|
-
var unbindToggle = (0, _bindEventListener.bind)(
|
|
178
|
+
var unbindToggle = (0, _bindEventListener.bind)(element, {
|
|
179
179
|
type: 'toggle',
|
|
180
180
|
listener: handleToggle
|
|
181
181
|
});
|
|
@@ -20,7 +20,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
20
20
|
/**
|
|
21
21
|
* Thin context wrapper that composes `Popover` + `useAnchorPosition`.
|
|
22
22
|
*
|
|
23
|
-
* Used inside the `<Popup>` compound
|
|
23
|
+
* Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
|
|
24
24
|
* and onClose from context. For standalone usage (tooltip, spotlight, flag),
|
|
25
25
|
* use `Popover` + `useAnchorPosition` directly.
|
|
26
26
|
*/
|
|
@@ -97,7 +97,7 @@ var PopupContent = exports.PopupContent = /*#__PURE__*/(0, _react.forwardRef)(fu
|
|
|
97
97
|
// ── Nested popover focus restoration fallback ──
|
|
98
98
|
// The browser only captures `previouslyFocusedElement` for the
|
|
99
99
|
// outermost popover="auto" in the stack. Inner (nested) popovers
|
|
100
|
-
// have shouldRestoreFocus=false, so the browser
|
|
100
|
+
// have shouldRestoreFocus=false, so the browser will not restore
|
|
101
101
|
// focus when they close.
|
|
102
102
|
//
|
|
103
103
|
// We detect this case by checking if focus is still inside the
|
|
@@ -26,7 +26,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
|
|
|
26
26
|
* from opening.
|
|
27
27
|
*
|
|
28
28
|
* If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
|
|
29
|
-
* instead
|
|
29
|
+
* instead - it hands you raw props via a render-prop and avoids
|
|
30
30
|
* `cloneElement` entirely.
|
|
31
31
|
*/
|
|
32
32
|
function PopupTrigger(_ref) {
|
|
@@ -40,7 +40,7 @@ function PopupTrigger(_ref) {
|
|
|
40
40
|
var childOnClick = /*#__PURE__*/(0, _react.isValidElement)(children) ? children.props.onClick : undefined;
|
|
41
41
|
|
|
42
42
|
// Use a ref to track the latest isOpen value so the click handler
|
|
43
|
-
//
|
|
43
|
+
// does not need isOpen in its dependency array (which would recreate
|
|
44
44
|
// the handler on every open/close, breaking cloneElement identity).
|
|
45
45
|
var isOpenRef = _react.default.useRef(isOpen);
|
|
46
46
|
isOpenRef.current = isOpen;
|
|
@@ -26,7 +26,7 @@ function useSimpleLightDismiss(_ref) {
|
|
|
26
26
|
var popoverRef = _ref.popoverRef,
|
|
27
27
|
isOpen = _ref.isOpen,
|
|
28
28
|
onClose = _ref.onClose;
|
|
29
|
-
// Keep a stable ref to onClose so the effect
|
|
29
|
+
// Keep a stable ref to onClose so the effect does not re-bind on every render.
|
|
30
30
|
var onCloseRef = (0, _react.useRef)(onClose);
|
|
31
31
|
onCloseRef.current = onClose;
|
|
32
32
|
(0, _react.useEffect)(function () {
|
|
@@ -14,7 +14,7 @@ import { getPlacement, placementToPositionArea } from '../internal/use-anchor-po
|
|
|
14
14
|
*
|
|
15
15
|
* Constraints:
|
|
16
16
|
* - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
|
|
17
|
-
* - `::before` and `::after` are consumed
|
|
17
|
+
* - `::before` and `::after` are consumed - consumers cannot use them
|
|
18
18
|
* - Arrow pseudo-elements use `background: inherit` from the popover element
|
|
19
19
|
*
|
|
20
20
|
* @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
|
|
@@ -184,7 +184,7 @@ function positionAreaToRuleName({
|
|
|
184
184
|
* that change both `position-area` and `margin` when flipping.
|
|
185
185
|
*
|
|
186
186
|
* This is required for the arrow technique because built-in keywords
|
|
187
|
-
* (`flip-block`, `flip-inline`) only flip `position-area`
|
|
187
|
+
* (`flip-block`, `flip-inline`) only flip `position-area` - they do
|
|
188
188
|
* not update the margin direction needed to reveal the correct arrow.
|
|
189
189
|
*/
|
|
190
190
|
function getTryFallbacks({
|
|
@@ -120,7 +120,12 @@ export const Dialog = /*#__PURE__*/forwardRef(function Dialog({
|
|
|
120
120
|
const escapedId = CSS.escape(dialogId);
|
|
121
121
|
return /*#__PURE__*/React.createElement("dialog", _extends({
|
|
122
122
|
ref: combinedRef,
|
|
123
|
-
id: dialogId
|
|
123
|
+
id: dialogId
|
|
124
|
+
// Modern browsers infer modal semantics from `.showModal()` but
|
|
125
|
+
// some assistive tech still keys off `aria-modal="true"`. Setting
|
|
126
|
+
// it explicitly is recommended by WAI-ARIA APG dialog pattern.
|
|
127
|
+
,
|
|
128
|
+
"aria-modal": "true",
|
|
124
129
|
"aria-label": label,
|
|
125
130
|
"aria-labelledby": label ? undefined : labelledBy,
|
|
126
131
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
@@ -39,7 +39,7 @@ function getFocusables({
|
|
|
39
39
|
container,
|
|
40
40
|
filter
|
|
41
41
|
}) {
|
|
42
|
-
return Array.from(container.querySelectorAll(selectors.focusable)).filter(
|
|
42
|
+
return Array.from(container.querySelectorAll(selectors.focusable)).filter(element => element instanceof HTMLElement).filter(element => !filter || filter(element, container));
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -13,6 +13,6 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export function combine(...cleanupFns) {
|
|
15
15
|
return function cleanup() {
|
|
16
|
-
cleanupFns.forEach(
|
|
16
|
+
cleanupFns.forEach(callback => callback === null || callback === void 0 ? void 0 : callback());
|
|
17
17
|
};
|
|
18
18
|
}
|
|
@@ -467,7 +467,19 @@ export function useAnchorPosition({
|
|
|
467
467
|
// ResizeObserver fires once the browser has real dimensions.
|
|
468
468
|
// Self-disconnects after one valid measurement; ongoing
|
|
469
469
|
// scroll/resize is handled by the window listeners below.
|
|
470
|
-
|
|
470
|
+
// `ResizeObserver` is missing in some non-DOM jest environments
|
|
471
|
+
// (e.g. post-office's `node` environment). Fall back to a no-op
|
|
472
|
+
// observer there — the scroll/resize listeners below still keep
|
|
473
|
+
// the popover positioned in the rare case the consumer also
|
|
474
|
+
// polyfilled `showPopover` but not `ResizeObserver`. Real
|
|
475
|
+
// browsers always have it.
|
|
476
|
+
const NoopResizeObserver = class {
|
|
477
|
+
observe() {}
|
|
478
|
+
unobserve() {}
|
|
479
|
+
disconnect() {}
|
|
480
|
+
};
|
|
481
|
+
const ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
|
|
482
|
+
const resizeObserver = new ResizeObserverImpl(() => {
|
|
471
483
|
if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
|
|
472
484
|
update();
|
|
473
485
|
resizeObserver.disconnect();
|
|
@@ -104,8 +104,8 @@ export function useAnimatedVisibility({
|
|
|
104
104
|
if (isOpen || !showChildren || !willAnimate) {
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
|
-
const
|
|
108
|
-
if (!
|
|
107
|
+
const element = elementRef.current;
|
|
108
|
+
if (!element) {
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
function finish() {
|
|
@@ -119,7 +119,7 @@ export function useAnimatedVisibility({
|
|
|
119
119
|
const fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
|
|
120
120
|
|
|
121
121
|
// Primary: listen for the CSS transition to complete
|
|
122
|
-
const unbind = bind(
|
|
122
|
+
const unbind = bind(element, {
|
|
123
123
|
type: 'transitionend',
|
|
124
124
|
listener: finish,
|
|
125
125
|
options: {
|
|
@@ -34,7 +34,7 @@ function roleRequiresFocusWrap(role) {
|
|
|
34
34
|
* elements within the container using wrapping navigation.
|
|
35
35
|
*
|
|
36
36
|
* Light dismiss (Escape, click outside) continues to work natively
|
|
37
|
-
* via `popover="auto"`
|
|
37
|
+
* via `popover="auto"` - this hook only intercepts Tab.
|
|
38
38
|
*
|
|
39
39
|
* Always call this hook unconditionally. The listener is only
|
|
40
40
|
* attached when the role requires focus wrapping, and is cleaned
|
|
@@ -45,11 +45,11 @@ export function useFocusWrap({
|
|
|
45
45
|
role
|
|
46
46
|
}) {
|
|
47
47
|
useEffect(() => {
|
|
48
|
-
const
|
|
49
|
-
if (!
|
|
48
|
+
const element = elementRef.current;
|
|
49
|
+
if (!element || !roleRequiresFocusWrap(role)) {
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
|
-
const unbind = bind(
|
|
52
|
+
const unbind = bind(element, {
|
|
53
53
|
type: 'keydown',
|
|
54
54
|
listener: event => {
|
|
55
55
|
if (event.key !== 'Tab') {
|
|
@@ -61,7 +61,7 @@ export function useFocusWrap({
|
|
|
61
61
|
// Try to move to the next/previous focusable element relative
|
|
62
62
|
// to the currently focused element within the container.
|
|
63
63
|
const next = getNextFocusable({
|
|
64
|
-
container:
|
|
64
|
+
container: element,
|
|
65
65
|
direction
|
|
66
66
|
});
|
|
67
67
|
if (next) {
|
|
@@ -73,9 +73,9 @@ export function useFocusWrap({
|
|
|
73
73
|
// focused element isn't in the focusable list). Fall back to
|
|
74
74
|
// the first or last focusable element depending on direction.
|
|
75
75
|
const fallback = direction === 'forwards' ? getFirstFocusable({
|
|
76
|
-
container:
|
|
76
|
+
container: element
|
|
77
77
|
}) : getLastFocusable({
|
|
78
|
-
container:
|
|
78
|
+
container: element
|
|
79
79
|
});
|
|
80
80
|
if (fallback) {
|
|
81
81
|
fallback.focus();
|
|
@@ -13,7 +13,7 @@ import { getFirstFocusable } from '../focus/focus';
|
|
|
13
13
|
* - no role / other roles: no focus movement
|
|
14
14
|
*
|
|
15
15
|
* Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
|
|
16
|
-
* attribute
|
|
16
|
+
* attribute - it only calls `.focus()` imperatively during commit, which
|
|
17
17
|
* has no effect on hidden popover content. Consumers must set the native
|
|
18
18
|
* attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
|
|
19
19
|
* React 19+ reflects the JSX prop as the HTML attribute automatically.
|
|
@@ -116,21 +116,21 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
116
116
|
// the browser processes light dismiss), read in the toggle handler.
|
|
117
117
|
const closeReasonRef = useRef('light-dismiss');
|
|
118
118
|
const handleToggle = useCallback(event => {
|
|
119
|
-
const
|
|
119
|
+
const element = ownRef.current;
|
|
120
120
|
if (event.newState === 'open') {
|
|
121
|
-
if (
|
|
121
|
+
if (element) {
|
|
122
122
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
|
|
123
123
|
isOpen: true,
|
|
124
|
-
element:
|
|
124
|
+
element: element
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
129
129
|
if (event.newState === 'closed') {
|
|
130
|
-
if (
|
|
130
|
+
if (element) {
|
|
131
131
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
|
|
132
132
|
isOpen: false,
|
|
133
|
-
element:
|
|
133
|
+
element: element
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -148,13 +148,13 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
148
148
|
}
|
|
149
149
|
}, [onClose, onOpenChange]);
|
|
150
150
|
useEffect(() => {
|
|
151
|
-
const
|
|
152
|
-
if (!
|
|
151
|
+
const element = ownRef.current;
|
|
152
|
+
if (!element) {
|
|
153
153
|
return;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
// Capture-phase: tag Escape before the browser processes light dismiss.
|
|
157
|
-
const unbindEscape = bind(
|
|
157
|
+
const unbindEscape = bind(element, {
|
|
158
158
|
type: 'keydown',
|
|
159
159
|
listener: event => {
|
|
160
160
|
if (event.key === 'Escape') {
|
|
@@ -165,7 +165,7 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
165
165
|
capture: true
|
|
166
166
|
}
|
|
167
167
|
});
|
|
168
|
-
const unbindToggle = bind(
|
|
168
|
+
const unbindToggle = bind(element, {
|
|
169
169
|
type: 'toggle',
|
|
170
170
|
listener: handleToggle
|
|
171
171
|
});
|
|
@@ -11,7 +11,7 @@ import { useMaybePopupContext } from './popup-context';
|
|
|
11
11
|
/**
|
|
12
12
|
* Thin context wrapper that composes `Popover` + `useAnchorPosition`.
|
|
13
13
|
*
|
|
14
|
-
* Used inside the `<Popup>` compound
|
|
14
|
+
* Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
|
|
15
15
|
* and onClose from context. For standalone usage (tooltip, spotlight, flag),
|
|
16
16
|
* use `Popover` + `useAnchorPosition` directly.
|
|
17
17
|
*/
|
|
@@ -88,7 +88,7 @@ export const PopupContent = /*#__PURE__*/forwardRef(function PopupContent({
|
|
|
88
88
|
// ── Nested popover focus restoration fallback ──
|
|
89
89
|
// The browser only captures `previouslyFocusedElement` for the
|
|
90
90
|
// outermost popover="auto" in the stack. Inner (nested) popovers
|
|
91
|
-
// have shouldRestoreFocus=false, so the browser
|
|
91
|
+
// have shouldRestoreFocus=false, so the browser will not restore
|
|
92
92
|
// focus when they close.
|
|
93
93
|
//
|
|
94
94
|
// We detect this case by checking if focus is still inside the
|
|
@@ -18,7 +18,7 @@ import { usePopupContext } from './popup-context';
|
|
|
18
18
|
* from opening.
|
|
19
19
|
*
|
|
20
20
|
* If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
|
|
21
|
-
* instead
|
|
21
|
+
* instead - it hands you raw props via a render-prop and avoids
|
|
22
22
|
* `cloneElement` entirely.
|
|
23
23
|
*/
|
|
24
24
|
export function PopupTrigger({
|
|
@@ -34,7 +34,7 @@ export function PopupTrigger({
|
|
|
34
34
|
const childOnClick = /*#__PURE__*/isValidElement(children) ? children.props.onClick : undefined;
|
|
35
35
|
|
|
36
36
|
// Use a ref to track the latest isOpen value so the click handler
|
|
37
|
-
//
|
|
37
|
+
// does not need isOpen in its dependency array (which would recreate
|
|
38
38
|
// the handler on every open/close, breaking cloneElement identity).
|
|
39
39
|
const isOpenRef = React.useRef(isOpen);
|
|
40
40
|
isOpenRef.current = isOpen;
|
|
@@ -21,7 +21,7 @@ export function useSimpleLightDismiss({
|
|
|
21
21
|
isOpen,
|
|
22
22
|
onClose
|
|
23
23
|
}) {
|
|
24
|
-
// Keep a stable ref to onClose so the effect
|
|
24
|
+
// Keep a stable ref to onClose so the effect does not re-bind on every render.
|
|
25
25
|
const onCloseRef = useRef(onClose);
|
|
26
26
|
onCloseRef.current = onClose;
|
|
27
27
|
useEffect(() => {
|
package/dist/esm/arrow/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { getPlacement, placementToPositionArea } from '../internal/use-anchor-po
|
|
|
14
14
|
*
|
|
15
15
|
* Constraints:
|
|
16
16
|
* - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
|
|
17
|
-
* - `::before` and `::after` are consumed
|
|
17
|
+
* - `::before` and `::after` are consumed - consumers cannot use them
|
|
18
18
|
* - Arrow pseudo-elements use `background: inherit` from the popover element
|
|
19
19
|
*
|
|
20
20
|
* @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
|
|
@@ -39,7 +39,7 @@ function positionAreaToRuleName(_ref) {
|
|
|
39
39
|
* that change both `position-area` and `margin` when flipping.
|
|
40
40
|
*
|
|
41
41
|
* This is required for the arrow technique because built-in keywords
|
|
42
|
-
* (`flip-block`, `flip-inline`) only flip `position-area`
|
|
42
|
+
* (`flip-block`, `flip-inline`) only flip `position-area` - they do
|
|
43
43
|
* not update the margin direction needed to reveal the correct arrow.
|
|
44
44
|
*/
|
|
45
45
|
function getTryFallbacks(_ref2) {
|
|
@@ -119,7 +119,12 @@ export var Dialog = /*#__PURE__*/forwardRef(function Dialog(_ref, ref) {
|
|
|
119
119
|
var escapedId = CSS.escape(dialogId);
|
|
120
120
|
return /*#__PURE__*/React.createElement("dialog", _extends({
|
|
121
121
|
ref: combinedRef,
|
|
122
|
-
id: dialogId
|
|
122
|
+
id: dialogId
|
|
123
|
+
// Modern browsers infer modal semantics from `.showModal()` but
|
|
124
|
+
// some assistive tech still keys off `aria-modal="true"`. Setting
|
|
125
|
+
// it explicitly is recommended by WAI-ARIA APG dialog pattern.
|
|
126
|
+
,
|
|
127
|
+
"aria-modal": "true",
|
|
123
128
|
"aria-label": label,
|
|
124
129
|
"aria-labelledby": label ? undefined : labelledBy,
|
|
125
130
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
package/dist/esm/focus/focus.js
CHANGED
|
@@ -38,10 +38,10 @@ var selectors = function () {
|
|
|
38
38
|
function getFocusables(_ref) {
|
|
39
39
|
var container = _ref.container,
|
|
40
40
|
filter = _ref.filter;
|
|
41
|
-
return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (
|
|
42
|
-
return
|
|
43
|
-
}).filter(function (
|
|
44
|
-
return !filter || filter(
|
|
41
|
+
return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (element) {
|
|
42
|
+
return element instanceof HTMLElement;
|
|
43
|
+
}).filter(function (element) {
|
|
44
|
+
return !filter || filter(element, container);
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -16,8 +16,8 @@ export function combine() {
|
|
|
16
16
|
cleanupFns[_key] = arguments[_key];
|
|
17
17
|
}
|
|
18
18
|
return function cleanup() {
|
|
19
|
-
cleanupFns.forEach(function (
|
|
20
|
-
return
|
|
19
|
+
cleanupFns.forEach(function (callback) {
|
|
20
|
+
return callback === null || callback === void 0 ? void 0 : callback();
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
23
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
1
3
|
/**
|
|
2
4
|
* Anchor positioning for top-layer popovers. See
|
|
3
5
|
* `notes/architecture/positioning.md` for the full model.
|
|
@@ -459,7 +461,29 @@ export function useAnchorPosition(_ref5) {
|
|
|
459
461
|
// ResizeObserver fires once the browser has real dimensions.
|
|
460
462
|
// Self-disconnects after one valid measurement; ongoing
|
|
461
463
|
// scroll/resize is handled by the window listeners below.
|
|
462
|
-
|
|
464
|
+
// `ResizeObserver` is missing in some non-DOM jest environments
|
|
465
|
+
// (e.g. post-office's `node` environment). Fall back to a no-op
|
|
466
|
+
// observer there — the scroll/resize listeners below still keep
|
|
467
|
+
// the popover positioned in the rare case the consumer also
|
|
468
|
+
// polyfilled `showPopover` but not `ResizeObserver`. Real
|
|
469
|
+
// browsers always have it.
|
|
470
|
+
var NoopResizeObserver = /*#__PURE__*/function () {
|
|
471
|
+
function NoopResizeObserver() {
|
|
472
|
+
_classCallCheck(this, NoopResizeObserver);
|
|
473
|
+
}
|
|
474
|
+
return _createClass(NoopResizeObserver, [{
|
|
475
|
+
key: "observe",
|
|
476
|
+
value: function observe() {}
|
|
477
|
+
}, {
|
|
478
|
+
key: "unobserve",
|
|
479
|
+
value: function unobserve() {}
|
|
480
|
+
}, {
|
|
481
|
+
key: "disconnect",
|
|
482
|
+
value: function disconnect() {}
|
|
483
|
+
}]);
|
|
484
|
+
}();
|
|
485
|
+
var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
|
|
486
|
+
var resizeObserver = new ResizeObserverImpl(function () {
|
|
463
487
|
if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
|
|
464
488
|
update();
|
|
465
489
|
resizeObserver.disconnect();
|
|
@@ -107,8 +107,8 @@ export function useAnimatedVisibility(_ref) {
|
|
|
107
107
|
if (isOpen || !showChildren || !willAnimate) {
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
|
-
var
|
|
111
|
-
if (!
|
|
110
|
+
var element = elementRef.current;
|
|
111
|
+
if (!element) {
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
function finish() {
|
|
@@ -122,7 +122,7 @@ export function useAnimatedVisibility(_ref) {
|
|
|
122
122
|
var fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
|
|
123
123
|
|
|
124
124
|
// Primary: listen for the CSS transition to complete
|
|
125
|
-
var unbind = bind(
|
|
125
|
+
var unbind = bind(element, {
|
|
126
126
|
type: 'transitionend',
|
|
127
127
|
listener: finish,
|
|
128
128
|
options: {
|
|
@@ -34,7 +34,7 @@ function roleRequiresFocusWrap(role) {
|
|
|
34
34
|
* elements within the container using wrapping navigation.
|
|
35
35
|
*
|
|
36
36
|
* Light dismiss (Escape, click outside) continues to work natively
|
|
37
|
-
* via `popover="auto"`
|
|
37
|
+
* via `popover="auto"` - this hook only intercepts Tab.
|
|
38
38
|
*
|
|
39
39
|
* Always call this hook unconditionally. The listener is only
|
|
40
40
|
* attached when the role requires focus wrapping, and is cleaned
|
|
@@ -44,11 +44,11 @@ export function useFocusWrap(_ref) {
|
|
|
44
44
|
var elementRef = _ref.elementRef,
|
|
45
45
|
role = _ref.role;
|
|
46
46
|
useEffect(function () {
|
|
47
|
-
var
|
|
48
|
-
if (!
|
|
47
|
+
var element = elementRef.current;
|
|
48
|
+
if (!element || !roleRequiresFocusWrap(role)) {
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
|
-
var unbind = bind(
|
|
51
|
+
var unbind = bind(element, {
|
|
52
52
|
type: 'keydown',
|
|
53
53
|
listener: function listener(event) {
|
|
54
54
|
if (event.key !== 'Tab') {
|
|
@@ -60,7 +60,7 @@ export function useFocusWrap(_ref) {
|
|
|
60
60
|
// Try to move to the next/previous focusable element relative
|
|
61
61
|
// to the currently focused element within the container.
|
|
62
62
|
var next = getNextFocusable({
|
|
63
|
-
container:
|
|
63
|
+
container: element,
|
|
64
64
|
direction: direction
|
|
65
65
|
});
|
|
66
66
|
if (next) {
|
|
@@ -72,9 +72,9 @@ export function useFocusWrap(_ref) {
|
|
|
72
72
|
// focused element isn't in the focusable list). Fall back to
|
|
73
73
|
// the first or last focusable element depending on direction.
|
|
74
74
|
var fallback = direction === 'forwards' ? getFirstFocusable({
|
|
75
|
-
container:
|
|
75
|
+
container: element
|
|
76
76
|
}) : getLastFocusable({
|
|
77
|
-
container:
|
|
77
|
+
container: element
|
|
78
78
|
});
|
|
79
79
|
if (fallback) {
|
|
80
80
|
fallback.focus();
|
|
@@ -13,7 +13,7 @@ import { getFirstFocusable } from '../focus/focus';
|
|
|
13
13
|
* - no role / other roles: no focus movement
|
|
14
14
|
*
|
|
15
15
|
* Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
|
|
16
|
-
* attribute
|
|
16
|
+
* attribute - it only calls `.focus()` imperatively during commit, which
|
|
17
17
|
* has no effect on hidden popover content. Consumers must set the native
|
|
18
18
|
* attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
|
|
19
19
|
* React 19+ reflects the JSX prop as the HTML attribute automatically.
|
|
@@ -117,21 +117,21 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
117
117
|
// the browser processes light dismiss), read in the toggle handler.
|
|
118
118
|
var closeReasonRef = useRef('light-dismiss');
|
|
119
119
|
var handleToggle = useCallback(function (event) {
|
|
120
|
-
var
|
|
120
|
+
var element = ownRef.current;
|
|
121
121
|
if (event.newState === 'open') {
|
|
122
|
-
if (
|
|
122
|
+
if (element) {
|
|
123
123
|
onOpenChange === null || onOpenChange === void 0 || onOpenChange({
|
|
124
124
|
isOpen: true,
|
|
125
|
-
element:
|
|
125
|
+
element: element
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
130
|
if (event.newState === 'closed') {
|
|
131
|
-
if (
|
|
131
|
+
if (element) {
|
|
132
132
|
onOpenChange === null || onOpenChange === void 0 || onOpenChange({
|
|
133
133
|
isOpen: false,
|
|
134
|
-
element:
|
|
134
|
+
element: element
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -149,13 +149,13 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
149
149
|
}
|
|
150
150
|
}, [onClose, onOpenChange]);
|
|
151
151
|
useEffect(function () {
|
|
152
|
-
var
|
|
153
|
-
if (!
|
|
152
|
+
var element = ownRef.current;
|
|
153
|
+
if (!element) {
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
// Capture-phase: tag Escape before the browser processes light dismiss.
|
|
158
|
-
var unbindEscape = bind(
|
|
158
|
+
var unbindEscape = bind(element, {
|
|
159
159
|
type: 'keydown',
|
|
160
160
|
listener: function listener(event) {
|
|
161
161
|
if (event.key === 'Escape') {
|
|
@@ -166,7 +166,7 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
166
166
|
capture: true
|
|
167
167
|
}
|
|
168
168
|
});
|
|
169
|
-
var unbindToggle = bind(
|
|
169
|
+
var unbindToggle = bind(element, {
|
|
170
170
|
type: 'toggle',
|
|
171
171
|
listener: handleToggle
|
|
172
172
|
});
|
|
@@ -11,7 +11,7 @@ import { useMaybePopupContext } from './popup-context';
|
|
|
11
11
|
/**
|
|
12
12
|
* Thin context wrapper that composes `Popover` + `useAnchorPosition`.
|
|
13
13
|
*
|
|
14
|
-
* Used inside the `<Popup>` compound
|
|
14
|
+
* Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
|
|
15
15
|
* and onClose from context. For standalone usage (tooltip, spotlight, flag),
|
|
16
16
|
* use `Popover` + `useAnchorPosition` directly.
|
|
17
17
|
*/
|
|
@@ -88,7 +88,7 @@ export var PopupContent = /*#__PURE__*/forwardRef(function PopupContent(_ref, re
|
|
|
88
88
|
// ── Nested popover focus restoration fallback ──
|
|
89
89
|
// The browser only captures `previouslyFocusedElement` for the
|
|
90
90
|
// outermost popover="auto" in the stack. Inner (nested) popovers
|
|
91
|
-
// have shouldRestoreFocus=false, so the browser
|
|
91
|
+
// have shouldRestoreFocus=false, so the browser will not restore
|
|
92
92
|
// focus when they close.
|
|
93
93
|
//
|
|
94
94
|
// We detect this case by checking if focus is still inside the
|
|
@@ -18,7 +18,7 @@ import { usePopupContext } from './popup-context';
|
|
|
18
18
|
* from opening.
|
|
19
19
|
*
|
|
20
20
|
* If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
|
|
21
|
-
* instead
|
|
21
|
+
* instead - it hands you raw props via a render-prop and avoids
|
|
22
22
|
* `cloneElement` entirely.
|
|
23
23
|
*/
|
|
24
24
|
export function PopupTrigger(_ref) {
|
|
@@ -32,7 +32,7 @@ export function PopupTrigger(_ref) {
|
|
|
32
32
|
var childOnClick = /*#__PURE__*/isValidElement(children) ? children.props.onClick : undefined;
|
|
33
33
|
|
|
34
34
|
// Use a ref to track the latest isOpen value so the click handler
|
|
35
|
-
//
|
|
35
|
+
// does not need isOpen in its dependency array (which would recreate
|
|
36
36
|
// the handler on every open/close, breaking cloneElement identity).
|
|
37
37
|
var isOpenRef = React.useRef(isOpen);
|
|
38
38
|
isOpenRef.current = isOpen;
|
|
@@ -20,7 +20,7 @@ export function useSimpleLightDismiss(_ref) {
|
|
|
20
20
|
var popoverRef = _ref.popoverRef,
|
|
21
21
|
isOpen = _ref.isOpen,
|
|
22
22
|
onClose = _ref.onClose;
|
|
23
|
-
// Keep a stable ref to onClose so the effect
|
|
23
|
+
// Keep a stable ref to onClose so the effect does not re-bind on every render.
|
|
24
24
|
var onCloseRef = useRef(onClose);
|
|
25
25
|
onCloseRef.current = onClose;
|
|
26
26
|
useEffect(function () {
|
|
@@ -118,7 +118,7 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
|
|
|
118
118
|
* the preset's named `@position-try` rules (which update both
|
|
119
119
|
* `position-area` and `margin` on flip) and sets `--ds-arrow-size`.
|
|
120
120
|
*
|
|
121
|
-
* Pass `null` to disable. Has no effect in the JS fallback path
|
|
121
|
+
* Pass `null` to disable. Has no effect in the JS fallback path -
|
|
122
122
|
* arrows are CSS-only.
|
|
123
123
|
*/
|
|
124
124
|
arrow?: TArrowPreset | null;
|
|
@@ -8,7 +8,7 @@ import { type RefObject } from 'react';
|
|
|
8
8
|
* elements within the container using wrapping navigation.
|
|
9
9
|
*
|
|
10
10
|
* Light dismiss (Escape, click outside) continues to work natively
|
|
11
|
-
* via `popover="auto"`
|
|
11
|
+
* via `popover="auto"` - this hook only intercepts Tab.
|
|
12
12
|
*
|
|
13
13
|
* Always call this hook unconditionally. The listener is only
|
|
14
14
|
* attached when the role requires focus wrapping, and is cleaned
|
|
@@ -7,7 +7,7 @@ import { type TPopupContentProps } from './types';
|
|
|
7
7
|
/**
|
|
8
8
|
* Thin context wrapper that composes `Popover` + `useAnchorPosition`.
|
|
9
9
|
*
|
|
10
|
-
* Used inside the `<Popup>` compound
|
|
10
|
+
* Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
|
|
11
11
|
* and onClose from context. For standalone usage (tooltip, spotlight, flag),
|
|
12
12
|
* use `Popover` + `useAnchorPosition` directly.
|
|
13
13
|
*/
|
|
@@ -17,7 +17,7 @@ import { type TPopupTriggerProps } from './types';
|
|
|
17
17
|
* from opening.
|
|
18
18
|
*
|
|
19
19
|
* If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
|
|
20
|
-
* instead
|
|
20
|
+
* instead - it hands you raw props via a render-prop and avoids
|
|
21
21
|
* `cloneElement` entirely.
|
|
22
22
|
*/
|
|
23
23
|
export declare function PopupTrigger({ children }: TPopupTriggerProps): ReactNode;
|
|
@@ -13,12 +13,12 @@ type TUseSimpleLightDismissOptions = {
|
|
|
13
13
|
/**
|
|
14
14
|
* Called when a light-dismiss event occurs.
|
|
15
15
|
*
|
|
16
|
-
* - `reason: 'escape'`
|
|
17
|
-
* - `reason: 'light-dismiss'`
|
|
16
|
+
* - `reason: 'escape'` - the user pressed the Escape key.
|
|
17
|
+
* - `reason: 'light-dismiss'` - the user clicked outside the popover.
|
|
18
18
|
*
|
|
19
19
|
* **Note:** This hook provides simple, standalone light dismiss that does not
|
|
20
20
|
* participate in the browser's `popover="auto"` dismiss stack. Every active
|
|
21
|
-
* instance will fire independently
|
|
21
|
+
* instance will fire independently - if multiple popovers use this hook,
|
|
22
22
|
* they will all receive dismiss events.
|
|
23
23
|
*/
|
|
24
24
|
onClose: (args: {
|
|
@@ -118,7 +118,7 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
|
|
|
118
118
|
* the preset's named `@position-try` rules (which update both
|
|
119
119
|
* `position-area` and `margin` on flip) and sets `--ds-arrow-size`.
|
|
120
120
|
*
|
|
121
|
-
* Pass `null` to disable. Has no effect in the JS fallback path
|
|
121
|
+
* Pass `null` to disable. Has no effect in the JS fallback path -
|
|
122
122
|
* arrows are CSS-only.
|
|
123
123
|
*/
|
|
124
124
|
arrow?: TArrowPreset | null;
|
|
@@ -8,7 +8,7 @@ import { type RefObject } from 'react';
|
|
|
8
8
|
* elements within the container using wrapping navigation.
|
|
9
9
|
*
|
|
10
10
|
* Light dismiss (Escape, click outside) continues to work natively
|
|
11
|
-
* via `popover="auto"`
|
|
11
|
+
* via `popover="auto"` - this hook only intercepts Tab.
|
|
12
12
|
*
|
|
13
13
|
* Always call this hook unconditionally. The listener is only
|
|
14
14
|
* attached when the role requires focus wrapping, and is cleaned
|
|
@@ -7,7 +7,7 @@ import { type TPopupContentProps } from './types';
|
|
|
7
7
|
/**
|
|
8
8
|
* Thin context wrapper that composes `Popover` + `useAnchorPosition`.
|
|
9
9
|
*
|
|
10
|
-
* Used inside the `<Popup>` compound
|
|
10
|
+
* Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
|
|
11
11
|
* and onClose from context. For standalone usage (tooltip, spotlight, flag),
|
|
12
12
|
* use `Popover` + `useAnchorPosition` directly.
|
|
13
13
|
*/
|
|
@@ -17,7 +17,7 @@ import { type TPopupTriggerProps } from './types';
|
|
|
17
17
|
* from opening.
|
|
18
18
|
*
|
|
19
19
|
* If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
|
|
20
|
-
* instead
|
|
20
|
+
* instead - it hands you raw props via a render-prop and avoids
|
|
21
21
|
* `cloneElement` entirely.
|
|
22
22
|
*/
|
|
23
23
|
export declare function PopupTrigger({ children }: TPopupTriggerProps): ReactNode;
|
|
@@ -13,12 +13,12 @@ type TUseSimpleLightDismissOptions = {
|
|
|
13
13
|
/**
|
|
14
14
|
* Called when a light-dismiss event occurs.
|
|
15
15
|
*
|
|
16
|
-
* - `reason: 'escape'`
|
|
17
|
-
* - `reason: 'light-dismiss'`
|
|
16
|
+
* - `reason: 'escape'` - the user pressed the Escape key.
|
|
17
|
+
* - `reason: 'light-dismiss'` - the user clicked outside the popover.
|
|
18
18
|
*
|
|
19
19
|
* **Note:** This hook provides simple, standalone light dismiss that does not
|
|
20
20
|
* participate in the browser's `popover="auto"` dismiss stack. Every active
|
|
21
|
-
* instance will fire independently
|
|
21
|
+
* instance will fire independently - if multiple popovers use this hook,
|
|
22
22
|
* they will all receive dismiss events.
|
|
23
23
|
*/
|
|
24
24
|
onClose: (args: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/top-layer",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.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",
|