Skip to content

Commit c7a695e

Browse files
chore: merge main (#5831)
1 parent 5e35222 commit c7a695e

File tree

17 files changed

+1297
-97
lines changed

17 files changed

+1297
-97
lines changed

.changeset/short-pans-know.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@spectrum-web-components/status-light': patch
3+
---
4+
5+
**Fixed**: Added missing `accent` and `cyan` variant to status light.

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ parameters:
2222
# 3. Commit this change to the PR branch where the changes exist.
2323
current_golden_images_hash:
2424
type: string
25-
default: eb24194a08a84696ddd7eb582d08118302b95ed7
25+
default: 71be19cab16d3ff600820e801341f14629ad06d9
2626
wireit_cache_name:
2727
type: string
2828
default: wireit

.cursor/rules/github-description.mdc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Use the following labels to categorize pull requests. Only use labels that exist
9393
- `Browser: Edge (Legacy)`: Issue with pre-chromium Edge
9494
- `Browser: FireFox`: Firefox browser issues
9595
- `Browser: Safari`: Safari browser issues
96+
- `iOS`: iOS-specific issues and bugs
9697

9798
### Development and process labels
9899

@@ -107,11 +108,9 @@ Common additional labels include:
107108

108109
- `chore`: Routine tasks, maintenance, or non-feature changes
109110
- `dependencies`: Updates or changes to project dependencies
110-
- `docs`: Documentation updates or improvements
111-
- `enhancement`: Improvements to existing features
112-
- `feature`: New feature implementations
111+
- `Documentation`: Documentation updates or improvements
112+
- `feature`: New feature implementations or improvements to existing features
113113
- `i18n`: Internationalization and localization work
114-
- `iOS`: iOS-specific issues and bugs
115114
- `mobile`: Mobile platform issues and responsive design
116115
- `performance`: Performance-related improvements or regressions
117116
- `refactor`: Code restructuring and refactoring work

.cursor/rules/jira-ticket.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ Use the following labels to categorize tickets appropriately:
185185
- `s2foundations`: Spectrum 2 Foundations related work
186186
- `spectrum2`: Spectrum 2 platform specific tasks
187187
- `team-processes`: Internal team workflow improvements
188-
- `testing`: Test implementation or testing infrastructure work
188+
- `test`: Test implementation or testing infrastructure work
189189
- `triage`: New tickets requiring team assessment and prioritization
190190
- `VoiceOver`: VoiceOver screen reader specific issues
191191

.github/ISSUE_TEMPLATE/feature_request.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: Feature request
22
description: Describe the feature you would like added
33
title: '[Feat]: '
4-
labels: [enhancement, triage, needs jira ticket]
4+
labels: [feature, triage, needs jira ticket]
55
# assignees:
66
body:
77
- type: markdown

.github/ISSUE_TEMPLATE/new_component.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: New component
22
description: Outline the requirements for a new component
33
title: '[NEW]: '
4-
labels: [missing components, triage, needs jira ticket]
4+
labels: [new component, triage, needs jira ticket]
55
# assignees:
66
body:
77
- type: markdown

first-gen/packages/action-menu/stories/action-menu.stories.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ selects.args = {
281281
open: true,
282282
};
283283
selects.decorators = [isOverlayOpen];
284+
selects.swc_vrt = {
285+
skip: true,
286+
};
284287

285288
export const iconOnly = (args: StoryArgs = {}): TemplateResult =>
286289
Template(args);

first-gen/packages/overlay/src/HoverController.ts

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,32 @@ import {
2020
lastInteractionType,
2121
} from './InteractionController.js';
2222

23-
const HOVER_DELAY = 300;
24-
2523
export class HoverController extends InteractionController {
2624
override type = InteractionTypes.hover;
2725

2826
private elementIds: string[] = [];
2927

30-
focusedin = false;
28+
private targetFocused = false;
3129

3230
private hoverTimeout?: ReturnType<typeof setTimeout>;
3331

34-
pointerentered = false;
32+
private hovering = false;
33+
34+
private overlayFocused = false;
3535

3636
handleKeyup(event: KeyboardEvent): void {
37-
if (event.code === 'Tab' || event.code === 'Escape') {
37+
if (event.code === 'Tab') {
3838
this.open = true;
39+
} else if (event.code === 'Escape') {
40+
if (this.open) {
41+
event.preventDefault();
42+
event.stopPropagation();
43+
this.open = false;
44+
// Return focus to trigger element
45+
if (this.target) {
46+
this.target.focus();
47+
}
48+
}
3949
}
4050
}
4151

@@ -52,23 +62,29 @@ export class HoverController extends InteractionController {
5262
}
5363

5464
this.open = true;
55-
this.focusedin = true;
65+
this.targetFocused = true;
5666
}
5767

5868
handleTargetFocusout(): void {
59-
this.focusedin = false;
60-
if (this.pointerentered) return;
61-
this.open = false;
69+
this.targetFocused = false;
70+
// Don't close immediately if pointer is over the content
71+
if (this.hovering) return;
72+
// Use delay to allow focus to move into overlay content
73+
this.doFocusleave();
6274
}
6375

64-
handleTargetPointerenter(): void {
76+
private clearCloseTimeout(): void {
6577
if (this.hoverTimeout) {
6678
clearTimeout(this.hoverTimeout);
6779
this.hoverTimeout = undefined;
6880
}
81+
}
82+
83+
handleTargetPointerenter(): void {
84+
this.clearCloseTimeout();
6985
if (this.overlay?.disabled) return;
7086
this.open = true;
71-
this.pointerentered = true;
87+
this.hovering = true;
7288
}
7389

7490
handleTargetPointerleave(): void {
@@ -78,16 +94,28 @@ export class HoverController extends InteractionController {
7894
// set a timeout once the pointer enters and the overlay is shown
7995
// give the user time to enter the overlay
8096
handleHostPointerenter(): void {
81-
if (this.hoverTimeout) {
82-
clearTimeout(this.hoverTimeout);
83-
this.hoverTimeout = undefined;
84-
}
97+
this.clearCloseTimeout();
8598
}
8699

87100
handleHostPointerleave(): void {
88101
this.doPointerleave();
89102
}
90103

104+
handleOverlayFocusin(): void {
105+
this.overlayFocused = true;
106+
// Clear any pending close timeout when focus enters overlay
107+
this.clearCloseTimeout();
108+
}
109+
110+
handleOverlayFocusout(): void {
111+
this.overlayFocused = false;
112+
// Don't close immediately if pointer is over the content or trigger has focus
113+
if (this.hovering) return;
114+
if (this.targetFocused && this.target.matches(':focus-visible')) return;
115+
// Use delay before closing
116+
this.doFocusleave();
117+
}
118+
91119
override prepareDescription(): void {
92120
// require "content" to apply relationship
93121
if (!this.overlay.elements.length) return;
@@ -138,14 +166,31 @@ export class HoverController extends InteractionController {
138166
};
139167
}
140168

141-
protected doPointerleave(): void {
142-
this.pointerentered = false;
143-
const triggerElement = this.target as HTMLElement;
144-
if (this.focusedin && triggerElement.matches(':focus-visible')) return;
145-
169+
private scheduleClose(): void {
146170
this.hoverTimeout = setTimeout(() => {
147171
this.open = false;
148-
}, HOVER_DELAY);
172+
}, 300);
173+
}
174+
175+
private doPointerleave(): void {
176+
this.hovering = false;
177+
const triggerElement = this.target as HTMLElement;
178+
if (this.targetFocused && triggerElement.matches(':focus-visible'))
179+
return;
180+
// Don't close if focus is within overlay content
181+
if (this.overlayFocused) return;
182+
183+
this.scheduleClose();
184+
}
185+
186+
private doFocusleave(): void {
187+
// Clear any existing timeout
188+
this.clearCloseTimeout();
189+
190+
// Use same delay as pointer interactions for consistency
191+
if (!this.targetFocused && !this.overlayFocused && !this.hovering) {
192+
this.scheduleClose();
193+
}
149194
}
150195

151196
override init(): void {
@@ -198,5 +243,20 @@ export class HoverController extends InteractionController {
198243
() => this.handleHostPointerleave(),
199244
{ signal }
200245
);
246+
this.overlay.addEventListener(
247+
'focusin',
248+
() => this.handleOverlayFocusin(),
249+
{ signal }
250+
);
251+
this.overlay.addEventListener(
252+
'focusout',
253+
() => this.handleOverlayFocusout(),
254+
{ signal }
255+
);
256+
this.overlay.addEventListener(
257+
'keyup',
258+
(event) => this.handleKeyup(event),
259+
{ signal }
260+
);
201261
}
202262
}

first-gen/packages/overlay/stories/overlay.stories.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import '@spectrum-web-components/dialog/sp-dialog.js';
2020
import '@spectrum-web-components/field-label/sp-field-label.js';
2121
import '@spectrum-web-components/icons-workflow/icons/sp-icon-magnify.js';
2222
import '@spectrum-web-components/icons-workflow/icons/sp-icon-open-in.js';
23+
import '@spectrum-web-components/link/sp-link.js';
2324
import {
2425
openOverlay,
2526
Overlay,
@@ -1654,6 +1655,92 @@ export const triggeredByOptimization = (): TemplateResult => {
16541655
`;
16551656
};
16561657

1658+
export const hoverWithInteractiveContent = (): TemplateResult => {
1659+
return html`
1660+
<div
1661+
style="display: flex; gap: 20px; flex-direction: column; padding: 40px;"
1662+
>
1663+
<!-- Hover with interactive buttons -->
1664+
<overlay-trigger triggered-by="hover" placement="right">
1665+
<sp-button slot="trigger">
1666+
Hover for interactive buttons
1667+
</sp-button>
1668+
<sp-popover slot="hover-content" tip>
1669+
<sp-dialog size="s" no-divider>
1670+
<h3 style="margin-top: 0;">Interactive content</h3>
1671+
<p>Tab into these buttons:</p>
1672+
<div
1673+
style="display: flex; gap: 8px; flex-direction: column;"
1674+
>
1675+
<sp-button>Action 1</sp-button>
1676+
<sp-button>Action 2</sp-button>
1677+
<sp-button>Action 3</sp-button>
1678+
</div>
1679+
</sp-dialog>
1680+
</sp-popover>
1681+
</overlay-trigger>
1682+
1683+
<!-- Hover with links -->
1684+
<overlay-trigger triggered-by="hover" placement="right">
1685+
<sp-button slot="trigger">
1686+
Hover for interactive links
1687+
</sp-button>
1688+
<sp-popover slot="hover-content" tip>
1689+
<sp-dialog size="s" no-divider>
1690+
<h3 style="margin-top: 0;">Quick links</h3>
1691+
<ul>
1692+
<li>
1693+
<sp-link href="#example1">
1694+
Example link 1
1695+
</sp-link>
1696+
</li>
1697+
<li>
1698+
<sp-link href="#example2">
1699+
Example link 2
1700+
</sp-link>
1701+
</li>
1702+
<li>
1703+
<sp-link href="#example3">
1704+
Example link 3
1705+
</sp-link>
1706+
</li>
1707+
</ul>
1708+
</sp-dialog>
1709+
</sp-popover>
1710+
</overlay-trigger>
1711+
1712+
<!-- Hover with action group (like Arrange icon example) -->
1713+
<overlay-trigger triggered-by="hover" placement="right">
1714+
<sp-button slot="trigger">Hover for action group</sp-button>
1715+
<sp-popover slot="hover-content" tip>
1716+
<sp-action-group
1717+
selects="single"
1718+
vertical
1719+
style="margin: var(--spectrum-spacing-200);"
1720+
>
1721+
<sp-action-button>
1722+
<sp-icon-magnify slot="icon"></sp-icon-magnify>
1723+
Send to Front
1724+
</sp-action-button>
1725+
<sp-action-button>
1726+
<sp-icon-magnify slot="icon"></sp-icon-magnify>
1727+
Send to Back
1728+
</sp-action-button>
1729+
<sp-action-button>
1730+
<sp-icon-magnify slot="icon"></sp-icon-magnify>
1731+
Align Center
1732+
</sp-action-button>
1733+
</sp-action-group>
1734+
</sp-popover>
1735+
</overlay-trigger>
1736+
</div>
1737+
`;
1738+
};
1739+
1740+
hoverWithInteractiveContent.swc_vrt = {
1741+
skip: true,
1742+
};
1743+
16571744
export const pickerInDialog = (): TemplateResult => {
16581745
return html`
16591746
<sp-button variant="primary" id="mybutton">Button popover</sp-button>

0 commit comments

Comments
 (0)