Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/funny-eggs-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@spectrum-web-components/overlay': minor
'@spectrum-web-components/core': minor
---

hover overlays should close with the Esc key when trigger is not focus
7 changes: 7 additions & 0 deletions 1st-gen/packages/overlay/src/OverlayStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ class OverlayStack {
if (event.code !== 'Escape') return;
if (!this.stack.length) return;
const last = this.stack[this.stack.length - 1];
if (last?.type === 'hint') {
// Close hint/tooltip overlays on "Escape" key and prevent further handling of the event.
event.preventDefault();
event.stopPropagation();
this.closeOverlay(last);
return;
}
if (last?.type === 'page') {
event.preventDefault();
return;
Expand Down
75 changes: 75 additions & 0 deletions 1st-gen/packages/overlay/test/overlay-trigger-hover.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,81 @@ describe('Overlay Trigger - Hover', () => {

expect(el.open).to.be.undefined;
});
it('closes the "tooltip" on "escape" keyup', async () => {
const opened = oneEvent(button, 'sp-opened');
button.dispatchEvent(
new MouseEvent('pointerenter', {
bubbles: true,
composed: true,
})
);
await waitUntil(
() => tooltip.open === true,
'tooltip should open',
{ timeout: 500 }
);
expect(tooltip.open).to.be.true;

button.dispatchEvent(
new MouseEvent('pointerenter', {
bubbles: true,
composed: true,
})
);
await waitUntil(
() => tooltip.open === true,
'tooltip should open',
{ timeout: 500 }
);
expect(tooltip.open).to.be.true;

button.dispatchEvent(
new MouseEvent('pointerleave', {
bubbles: true,
composed: true,
})
);
await elementUpdated(tooltip);

button.dispatchEvent(
new MouseEvent('pointerenter', {
bubbles: true,
composed: true,
})
);
await elementUpdated(tooltip);

tooltip.dispatchEvent(
new MouseEvent('pointerleave', {
bubbles: true,
composed: true,
})
);
await elementUpdated(tooltip);

button.dispatchEvent(
new MouseEvent('pointerenter', {
bubbles: true,
composed: true,
})
);
await opened;

expect(el.open).to.equal('hover');

// make sure escape keyup closes the tooltip even when the button does not have focus
const body = el.ownerDocument.body;
body.focus();
const closed = oneEvent(button, 'sp-closed');
const escapeKeyup = new KeyboardEvent('keyup', {
key: 'Escape',
bubbles: true,
composed: true,
});
body.dispatchEvent(escapeKeyup);
await closed;
expect(el.open).to.be.undefined;
});
});
it('persists hover content', async () => {
const el = await fixture<OverlayTrigger>(
Expand Down
12 changes: 12 additions & 0 deletions 2nd-gen/packages/core/shared/base/version.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
/**
* Copyright 2025 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

// Generated by genversion.
export const version = '1.10.0';