Skip to content

Commit 0010699

Browse files
committed
chore: merge main
1 parent 2074807 commit 0010699

File tree

11 files changed

+325
-92
lines changed

11 files changed

+325
-92
lines changed

.changeset/weak-streets-raise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@spectrum-web-components/overlay': patch
3+
---
4+
5+
- **Fixed**: Expanded `<overlay-trigger>` `type` property to accept all overlay types ('auto', 'hint', 'manual', 'modal', 'page') instead of the incorrect, previous restricted subset.

1st-gen/packages/combobox/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ For exceptional cases, provide an accessible label via the `label` attribute.
236236

237237
#### Provide help text and tooltips in the correct location
238238

239-
It is [not currently possible](https://w3c.github.io/webcomponents-cg/#cross-root-aria) to provide accessible ARIA references between elements in different shadow roots. To ensure proper association between elements, help text must be included via the `slot="help-text"` or `slot="help-text-negative"` and tooltips must be included via the `slot="tooltip"`.
239+
It is [not currently possible](https://w3c.github.io/webcomponents-cg/#cross-root-aria) to provide accessible ARIA references between elements in different shadow roots. To ensure proper association between elements, help text must be included via the `slot="help-text"` or `slot="negative-help-text"` and tooltips must be included via the `slot="tooltip"`.
240240

241241
See [help text](../help-text) and [tooltip](../tooltip) for more information.
242242

1st-gen/packages/help-text/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ For help text, usually the error is related to something that needs to be fixed
100100
<sp-help-text slot="help-text">
101101
Create a password with at least 8 characters.
102102
</sp-help-text>
103-
<sp-help-text variant="negative" slot="help-text-negative">
103+
<sp-help-text variant="negative" slot="negative-help-text">
104104
Passwords must be at least 8 characters
105105
</sp-help-text>
106106
</sp-textfield>
@@ -149,12 +149,12 @@ When the content associated to the element is disabled, use the `disabled` attri
149149

150150
Good, descriptive help text includes 1-2 short sentences of information such as:
151151

152-
- An overall description of an input field or controls
153-
- Hints for what kind of information needs to be inputted or selected
154-
- Specific formatting examples or requirements
152+
- An overall description of an input field or controls
153+
- Hints for what kind of information needs to be inputted or selected
154+
- Specific formatting examples or requirements
155155

156156
#### Ensure help text and field share the same root
157157

158-
It is [not currently possible](https://w3c.github.io/webcomponents-cg/#cross-root-aria) to provide accessible ARIA references between elements in different shadow roots. To ensure proper association between elements, help text must be included via the `slot="help-text"` or `slot="help-text-negative"` in an `<sp-text-field>`, `<sp-field-group>`, `<sp-combobox>` or `<sp-picker>`.
158+
It is [not currently possible](https://w3c.github.io/webcomponents-cg/#cross-root-aria) to provide accessible ARIA references between elements in different shadow roots. To ensure proper association between elements, help text must be included via the `slot="help-text"` or `slot="negative-help-text"` in an `<sp-text-field>`, `<sp-field-group>`, `<sp-combobox>` or `<sp-picker>`.
159159

160160
To add help text to your own custom element, see [Help Text Mixin](./help-text-mixin/).

1st-gen/packages/overlay/README.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,42 @@ Some Overlays will always be passed focus (e.g. modal or page Overlays). When th
267267

268268
#### trigger
269269

270-
The `trigger` option accepts an `HTMLElement` or a `VirtualTrigger` from which to position the Overlay.
270+
The `trigger` attribute accepts a string ID reference for the trigger element combined with the interaction type.
271+
272+
The format is `"elementId@interaction"`, where:
273+
274+
- `elementId` is the ID of the HTML element to use as the trigger
275+
- `interaction` is required and can be `click`, `hover`, or `longpress`
276+
277+
Examples:
278+
279+
```html
280+
<sp-button id="my-button">Open Overlay</sp-button>
281+
282+
<!-- Explicit click interaction -->
283+
<sp-overlay trigger="my-button@click" placement="top-start">
284+
<sp-popover>Click popover</sp-popover>
285+
</sp-overlay>
286+
287+
<!-- Explicit hover interaction -->
288+
<sp-overlay trigger="my-button@hover" placement="right-start">
289+
<sp-popover>Hover popover</sp-popover>
290+
</sp-overlay>
291+
292+
<!-- Explicit longpress interaction -->
293+
<sp-overlay trigger="my-button@longpress" placement="bottom-start">
294+
<sp-popover>Longpress popover</sp-popover>
295+
</sp-overlay>
296+
```
297+
298+
#### triggerElement
299+
300+
The `triggerElement` property accepts an `HTMLElement` or a `VirtualTrigger` from which to position the Overlay.
271301

272302
- You can import the `VirtualTrigger` class from the overlay package to create a virtual trigger that can be used to position an Overlay. This is useful when you want to position an Overlay relative to a point on the screen that is not an element in the DOM, like the mouse cursor.
273303

304+
#### type
305+
274306
The `type` of an Overlay outlines a number of things about the interaction model within which it works:
275307

276308
<sp-tabs selected="modal" auto label="Type attribute options">
@@ -529,7 +561,7 @@ This means that in both cases, if the transition is meant to be a part of the op
529561
placement=${Placement}
530562
receives-focus=${'true' | 'false' | 'auto' (default)
531563
trigger=${string | ${string}@${string}}
532-
.triggerElement=${HTMLElement}
564+
.triggerElement=${HTMLElement | VirtualTrigger}
533565
.triggerInteraction=${'click' | 'longpress' | 'hover'}
534566
type=${'auto' | 'hint' | 'manual' | 'modal' | 'page'}
535567
?allow-outside-click=${boolean}

1st-gen/packages/overlay/overlay-trigger.md

Lines changed: 103 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -77,78 +77,129 @@ When using the `placement` attribute of an `<overlay-trigger>` (`"top" |"top-sta
7777

7878
#### Type
7979

80-
<sp-tabs selected="inline" auto label="Type attribute options">
81-
<sp-tab value="inline">Inline</sp-tab>
82-
<sp-tab-panel value="inline">
80+
The `type` of an Overlay outlines a number of things about the interaction model within which it works:
8381

84-
`'inline'` type inserts the overlay after the trigger in the tab order. This creates a natural flow where:
82+
**Note:** The `type` attribute only affects click-triggered overlays. Hover overlays always use `hint` type behavior, and longpress overlays always use `auto` type behavior. For more control over hover and longpress overlay types, use `<sp-overlay>` directly.
8583

86-
- Forward tab: Goes to the next logical element
87-
- Backward tab (shift): Returns to the trigger
84+
<sp-tabs selected="modal" auto label="Type attribute options">
85+
<sp-tab value="modal">Modal</sp-tab>
86+
<sp-tab-panel value="modal">
87+
88+
`'modal'` Overlays create a modal context that traps focus within the content and prevents interaction with the rest of the page. The overlay manages focus trapping and accessibility features like `aria-modal="true"` to ensure proper screen reader behavior.
89+
90+
They should be used when you need to ensure that the user has interacted with the content of the Overlay before continuing with their work. This is commonly used for dialogs that require a user to confirm or cancel an action before continuing.
8891

8992
```html
90-
<overlay-trigger type="inline" placement="bottom">
91-
<sp-button slot="trigger">Open Menu</sp-button>
92-
<sp-popover slot="click-content">
93-
<sp-menu>
94-
<sp-menu-item>Option 1</sp-menu-item>
95-
<sp-menu-item>Option 2</sp-menu-item>
96-
</sp-menu>
97-
</sp-popover>
93+
<overlay-trigger type="modal" triggered-by="click">
94+
<sp-button slot="trigger">Open modal</sp-button>
95+
<sp-dialog-wrapper
96+
slot="click-content"
97+
headline="Signin form"
98+
dismissable
99+
underlay
100+
>
101+
<p>I am a modal type overlay.</p>
102+
<sp-field-label>Enter your email</sp-field-label>
103+
<sp-textfield placeholder="[email protected]"></sp-textfield>
104+
<sp-action-button
105+
onClick="
106+
this.dispatchEvent(
107+
new Event('close', {
108+
bubbles: true,
109+
composed: true,
110+
})
111+
);
112+
"
113+
>
114+
Sign in
115+
</sp-action-button>
116+
</sp-dialog-wrapper>
98117
</overlay-trigger>
99118
```
100119

101120
</sp-tab-panel>
102-
<sp-tab value="replace">Replace</sp-tab>
103-
<sp-tab-panel value="replace">
121+
<sp-tab value="page">Page</sp-tab>
122+
<sp-tab-panel value="page">
104123

105-
`'replace'` type inserts the overlay as if it were the trigger itself in the tab order. This means:
124+
`'page'` Overlays behave similarly to `'modal'` Overlays by creating a modal context and trapping focus, but they will not be allowed to close via the "light dismiss" algorithm (e.g. the Escape key).
106125

107-
- Forward tab: Goes to the next logical element
108-
- Backward tab (shift): Goes to the element before the trigger
126+
A page overlay could be used for a full-screen menu on a mobile website. When the user clicks on the menu button, the entire screen is covered with the menu options.
109127

110128
```html
111-
<overlay-trigger type="replace" placement="bottom">
112-
<sp-button slot="trigger">Show Details</sp-button>
113-
<sp-popover slot="click-content">
114-
<sp-dialog>
115-
<p>Details panel that replaces trigger in tab order</p>
116-
<sp-button
117-
onclick="this.dispatchEvent(new Event('close', { bubbles: true, composed: true }))"
118-
>
119-
Close
120-
</sp-button>
121-
</sp-dialog>
129+
<overlay-trigger type="page" triggered-by="click">
130+
<sp-button slot="trigger">Open page</sp-button>
131+
<sp-dialog-wrapper
132+
slot="click-content"
133+
headline="Full screen menu"
134+
mode="fullscreenTakeover"
135+
cancel-label="Close"
136+
>
137+
<p>I am a page type overlay.</p>
138+
</sp-dialog-wrapper>
139+
</overlay-trigger>
140+
```
141+
142+
</sp-tab-panel>
143+
<sp-tab value="hint">Hint</sp-tab>
144+
<sp-tab-panel value="hint">
145+
146+
`'hint'` Overlays are much like tooltips so they are not just ephemeral, but they are delivered primarily as a visual helper and exist outside of the tab order. In this way, be sure _not_ to place interactive content within this type of Overlay.
147+
148+
This overlay type does not accept focus and does not interfere with the user's interaction with the rest of the page.
149+
150+
```html
151+
<overlay-trigger type="hint" triggered-by="hover">
152+
<sp-button slot="trigger">Open hint</sp-button>
153+
<sp-tooltip slot="click-content">
154+
I am a hint type overlay. I am not interactive and will close when the
155+
user interacts with the page.
156+
</sp-tooltip>
157+
</overlay-trigger>
158+
```
159+
160+
</sp-tab-panel>
161+
<sp-tab value="auto">Auto</sp-tab>
162+
<sp-tab-panel value="auto">
163+
164+
`'auto'` Overlays provide a place for content that is ephemeral _and_ interactive. These Overlays can accept focus and remain open while interacting with their content. They will close when focus moves outside the overlay or when clicking elsewhere on the page.
165+
166+
```html
167+
<overlay-trigger type="auto" triggered-by="click" placement="bottom">
168+
<sp-button slot="trigger">Open overlay</sp-button>
169+
<sp-popover slot="click-content" dialog>
170+
<p>
171+
My slider in overlay element:
172+
<sp-slider label="Slider Label - Editable" editable></sp-slider>
173+
</p>
122174
</sp-popover>
123175
</overlay-trigger>
124176
```
125177

126178
</sp-tab-panel>
127-
<sp-tab value="modal">Modal</sp-tab>
128-
<sp-tab-panel value="modal">
179+
<sp-tab value="manual">Manual</sp-tab>
180+
<sp-tab-panel value="manual">
181+
182+
`'manual'` Overlays act much like `'auto'` Overlays, but do not close when losing focus or interacting with other parts of the page.
129183

130-
`'modal'` type creates a separate tab order and traps focus within the overlay content until the required interaction is complete. This is ideal for important interactions that need user attention.
184+
Note: When a `'manual'` Overlay is at the top of the "overlay stack", it will still respond to the Escape key and close.
131185

132186
```html
133-
<overlay-trigger type="modal">
134-
<sp-button slot="trigger">Open Settings</sp-button>
135-
<sp-dialog-wrapper
136-
slot="click-content"
137-
headline="Settings"
138-
dismissable
139-
underlay
140-
>
141-
<sp-field-label>Theme</sp-field-label>
142-
<sp-picker>
143-
<sp-menu-item>Light</sp-menu-item>
144-
<sp-menu-item>Dark</sp-menu-item>
145-
</sp-picker>
146-
<sp-button
147-
onclick="this.dispatchEvent(new Event('close', { bubbles: true, composed: true }))"
148-
>
149-
Save
150-
</sp-button>
151-
</sp-dialog-wrapper>
187+
<style>
188+
.chat-container {
189+
position: fixed;
190+
bottom: 1em;
191+
left: 1em;
192+
}
193+
</style>
194+
<overlay-trigger type="manual" triggered-by="click">
195+
<sp-button slot="trigger">Open manual</sp-button>
196+
<sp-popover slot="click-content" class="chat-container">
197+
<sp-dialog dismissable>
198+
<span slot="heading">Chat Window</span>
199+
<sp-textfield placeholder="Enter your message"></sp-textfield>
200+
<sp-action-button>Send</sp-action-button>
201+
</sp-dialog>
202+
</sp-popover>
152203
</overlay-trigger>
153204
```
154205

1st-gen/packages/overlay/src/OverlayTrigger.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ import type { Placement } from '@floating-ui/dom';
2626

2727
import type { BeforetoggleOpenEvent } from './events.js';
2828
import type { Overlay } from './Overlay.js';
29-
import type { OverlayTriggerInteractions } from './overlay-types';
29+
import type { OverlayTypes } from './overlay-types.js';
30+
// eslint-disable-next-line import/no-extraneous-dependencies
3031
import '@spectrum-web-components/overlay/sp-overlay.js';
3132

3233
import overlayTriggerStyles from './overlay-trigger.css.js';
@@ -90,7 +91,7 @@ export class OverlayTrigger extends SpectrumElement {
9091
public placement?: Placement;
9192

9293
@property()
93-
public type?: OverlayTriggerInteractions;
94+
public type?: OverlayTypes;
9495

9596
@property({ type: Number })
9697
public offset = 6;
@@ -225,7 +226,7 @@ export class OverlayTrigger extends SpectrumElement {
225226
.placement=${this.clickPlacement || this.placement}
226227
.triggerElement=${this.targetContent[0]}
227228
.triggerInteraction=${'click'}
228-
.type=${this.type !== 'modal' ? 'auto' : 'modal'}
229+
.type=${this.type || 'auto'}
229230
@beforetoggle=${this.handleBeforetoggle}
230231
.receivesFocus=${this.receivesFocus}
231232
>

1st-gen/packages/overlay/src/overlay-types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ export { Placement };
2323

2424
export type OverlayTypes = 'auto' | 'hint' | 'manual' | 'modal' | 'page';
2525

26+
// Constant array for runtime use (tests, validation, etc.)
27+
export const OVERLAY_TYPES = [
28+
'auto',
29+
'hint',
30+
'manual',
31+
'modal',
32+
'page',
33+
] as const satisfies readonly OverlayTypes[];
34+
2635
export type TriggerInteraction = 'click' | 'longpress' | 'hover';
2736

2837
export type TriggerInteractions = OverlayTypes;

1st-gen/packages/overlay/test/index.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import { Button } from '@spectrum-web-components/button';
2424
import '@spectrum-web-components/button/sp-button.js';
2525
import '@spectrum-web-components/dialog/sp-dialog.js';
2626
import {
27+
OVERLAY_TYPES,
2728
OverlayTrigger,
28-
TriggerInteractions,
2929
} from '@spectrum-web-components/overlay';
3030
import { Popover } from '@spectrum-web-components/popover';
3131
import '@spectrum-web-components/popover/sp-popover.js';
@@ -113,10 +113,10 @@ export const runOverlayTriggerTests = (type: string): void => {
113113

114114
this.innerTrigger = this.testDiv.querySelector(
115115
'#inner-trigger'
116-
) as OverlayTrigger;
116+
)! as OverlayTrigger;
117117
this.outerTrigger = this.testDiv.querySelector(
118118
'#trigger'
119-
) as OverlayTrigger;
119+
)! as OverlayTrigger;
120120
this.innerButton = this.testDiv.querySelector(
121121
'#inner-button'
122122
) as Button;
@@ -213,20 +213,19 @@ export const runOverlayTriggerTests = (type: string): void => {
213213
).to.be.true;
214214
});
215215

216-
['modal', 'replace', 'inline'].map((type: string) => {
216+
OVERLAY_TYPES.map((type) => {
217217
it(`opens a popover - [type="${type}"]`, async function () {
218-
this.outerTrigger.type = type as Extract<
219-
TriggerInteractions,
220-
'inline' | 'modal' | 'replace'
221-
>;
222-
await elementUpdated(this.outerTrigger);
218+
const outerTrigger = this.outerTrigger as OverlayTrigger;
219+
220+
outerTrigger.type = type;
221+
await elementUpdated(outerTrigger);
223222
expect(
224223
await isOnTopLayer(this.outerClickContent),
225224
'popover not available at point'
226225
).to.be.false;
227226

228227
expect(this.outerButton).to.exist;
229-
const opened = oneEvent(this.outerTrigger, 'sp-opened');
228+
const opened = oneEvent(outerTrigger, 'sp-opened');
230229
this.outerButton.click();
231230
await opened;
232231
expect(

1st-gen/packages/picker/test/index.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,11 +1085,9 @@ export function runPickerTests(): void {
10851085
el.insertAdjacentElement('afterend', input);
10861086

10871087
el.focus();
1088-
if (!isWebKit()) {
1089-
await sendTabKey();
1090-
expect(document.activeElement).to.equal(input);
1091-
await sendShiftTabKey();
1092-
}
1088+
await sendTabKey();
1089+
expect(document.activeElement).to.equal(input);
1090+
await sendShiftTabKey();
10931091
expect(document.activeElement).to.equal(el);
10941092
const opened = oneEvent(el, 'sp-opened');
10951093
await sendKeys({ press: 'Enter' });
@@ -1124,11 +1122,9 @@ export function runPickerTests(): void {
11241122
el.insertAdjacentElement('afterend', input);
11251123

11261124
el.focus();
1127-
if (!isWebKit()) {
1128-
await sendTabKey();
1129-
expect(document.activeElement).to.equal(input);
1130-
await sendKeys({ press: 'Shift+Tab' });
1131-
}
1125+
await sendTabKey();
1126+
expect(document.activeElement).to.equal(input);
1127+
await sendKeys({ press: 'Shift+Tab' });
11321128
expect(document.activeElement).to.equal(el);
11331129
const opened = oneEvent(el, 'sp-opened');
11341130
await sendKeys({ down: 'Enter' });

0 commit comments

Comments
 (0)