@spectrum-web-components/tray 1.10.0 → 1.11.0-snapshot.20251106093044
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/README.md +80 -3
- package/custom-elements.json +69 -0
- package/package.json +6 -6
- package/src/Tray.d.ts +27 -0
- package/src/Tray.dev.js +72 -2
- package/src/Tray.dev.js.map +2 -2
- package/src/Tray.js +9 -3
- package/src/Tray.js.map +3 -3
- package/src/tray.css.dev.js +1 -1
- package/src/tray.css.dev.js.map +1 -1
- package/src/tray.css.js +1 -1
- package/src/tray.css.js.map +1 -1
package/README.md
CHANGED
|
@@ -7,19 +7,19 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/@spectrum-web-components/tray)
|
|
8
8
|
[](https://bundlephobia.com/result?p=@spectrum-web-components/tray)
|
|
9
9
|
|
|
10
|
-
```
|
|
10
|
+
```zsh
|
|
11
11
|
yarn add @spectrum-web-components/tray
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
Import the side effectful registration of `<sp-tray>` via:
|
|
15
15
|
|
|
16
|
-
```
|
|
16
|
+
```js
|
|
17
17
|
import '@spectrum-web-components/tray/sp-tray.js';
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
When looking to leverage the `Tray` base class as a type and/or for extension purposes, do so via:
|
|
21
21
|
|
|
22
|
-
```
|
|
22
|
+
```js
|
|
23
23
|
import { Tray } from '@spectrum-web-components/tray';
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -70,3 +70,80 @@ A tray has a single default `slot`.
|
|
|
70
70
|
### Accessibility
|
|
71
71
|
|
|
72
72
|
`<sp-tray>` presents a page blocking experience and should be opened with the `Overlay` API using the `modal` interaction to ensure that the content appropriately manages the presence of other content in the tab order of the page and the availability of that content for a screen reader.
|
|
73
|
+
|
|
74
|
+
#### Auto-detection behavior
|
|
75
|
+
|
|
76
|
+
By default, `<sp-tray>` automatically detects whether its slotted content includes keyboard-accessible dismiss buttons (like `<sp-button>`, `<sp-close-button>`, or HTML `<button>` elements). When no dismiss buttons are found, the tray renders visually hidden dismiss buttons before and after its content to support mobile screen readers, particularly VoiceOver on iOS where users navigate through interactive elements sequentially.
|
|
77
|
+
|
|
78
|
+
These built-in dismiss buttons:
|
|
79
|
+
|
|
80
|
+
- Are visually hidden but accessible to screen readers
|
|
81
|
+
- Allow mobile screen reader users to easily dismiss the tray from either the beginning or end of the content
|
|
82
|
+
- Are labeled "Dismiss" for clear screen reader announcements
|
|
83
|
+
|
|
84
|
+
This dismiss helper pattern is also implemented in the [`<sp-picker>`](https://opensource.adobe.com/spectrum-web-components/components/picker/) component, which uses the same approach when rendering menu content in a tray on mobile devices.
|
|
85
|
+
|
|
86
|
+
<sp-tabs selected="auto" auto label="Dismiss helper examples">
|
|
87
|
+
<sp-tab value="auto">Content has no buttons</sp-tab>
|
|
88
|
+
<sp-tab-panel value="auto">
|
|
89
|
+
|
|
90
|
+
This example shows the default behavior where the tray automatically detects that the menu content lacks dismiss buttons and renders visually hidden helpers. Screen readers will announce them as "Dismiss, button" and these helpers are keyboard accessible.
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<overlay-trigger type="modal">
|
|
94
|
+
<sp-button slot="trigger" variant="secondary">
|
|
95
|
+
Toggle menu content
|
|
96
|
+
</sp-button>
|
|
97
|
+
<sp-tray slot="click-content">
|
|
98
|
+
<sp-menu style="width: 100%">
|
|
99
|
+
<sp-menu-item>Deselect</sp-menu-item>
|
|
100
|
+
<sp-menu-item>Select Inverse</sp-menu-item>
|
|
101
|
+
<sp-menu-item>Feather...</sp-menu-item>
|
|
102
|
+
<sp-menu-item>Select and Mask...</sp-menu-item>
|
|
103
|
+
</sp-menu>
|
|
104
|
+
</sp-tray>
|
|
105
|
+
</overlay-trigger>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
</sp-tab-panel>
|
|
109
|
+
<sp-tab value="with-buttons">Content has buttons</sp-tab>
|
|
110
|
+
<sp-tab-panel value="with-buttons">
|
|
111
|
+
|
|
112
|
+
This example shows auto-detection recognizing that the dialog has its own dismiss functionality, so no additional helpers are rendered.
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<overlay-trigger type="modal">
|
|
116
|
+
<sp-button slot="trigger" variant="secondary">
|
|
117
|
+
Toggle dialog content
|
|
118
|
+
</sp-button>
|
|
119
|
+
<sp-tray slot="click-content">
|
|
120
|
+
<sp-dialog size="s" dismissable>
|
|
121
|
+
<h2 slot="heading">New messages</h2>
|
|
122
|
+
You have 5 new messages.
|
|
123
|
+
</sp-dialog>
|
|
124
|
+
</sp-tray>
|
|
125
|
+
</overlay-trigger>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
</sp-tab-panel>
|
|
129
|
+
<sp-tab value="force-hide">Manual override</sp-tab>
|
|
130
|
+
<sp-tab-panel value="force-hide">
|
|
131
|
+
|
|
132
|
+
Set `has-keyboard-dismiss` (or `has-keyboard-dismiss="true"`) to prevent the tray from rendering visually hidden dismiss helpers, even when no buttons are detected. You are then responsible for ensuring that your tray content has keyboard-accessible dismiss functionality.
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<overlay-trigger type="modal">
|
|
136
|
+
<sp-button slot="trigger" variant="secondary">
|
|
137
|
+
Toggle without helpers
|
|
138
|
+
</sp-button>
|
|
139
|
+
<sp-tray slot="click-content" has-keyboard-dismiss>
|
|
140
|
+
<p>
|
|
141
|
+
Custom content that should have custom dismiss functionality, even
|
|
142
|
+
though the tray didn't detect buttons in this slot.
|
|
143
|
+
</p>
|
|
144
|
+
</sp-tray>
|
|
145
|
+
</overlay-trigger>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
</sp-tab-panel>
|
|
149
|
+
</sp-tabs>
|
package/custom-elements.json
CHANGED
|
@@ -67,6 +67,14 @@
|
|
|
67
67
|
},
|
|
68
68
|
"privacy": "private"
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
"kind": "field",
|
|
72
|
+
"name": "contentSlot",
|
|
73
|
+
"type": {
|
|
74
|
+
"text": "HTMLSlotElement"
|
|
75
|
+
},
|
|
76
|
+
"privacy": "private"
|
|
77
|
+
},
|
|
70
78
|
{
|
|
71
79
|
"kind": "method",
|
|
72
80
|
"name": "focus",
|
|
@@ -106,6 +114,58 @@
|
|
|
106
114
|
}
|
|
107
115
|
}
|
|
108
116
|
},
|
|
117
|
+
{
|
|
118
|
+
"kind": "field",
|
|
119
|
+
"name": "hasKeyboardDismissButton",
|
|
120
|
+
"type": {
|
|
121
|
+
"text": "boolean"
|
|
122
|
+
},
|
|
123
|
+
"privacy": "public",
|
|
124
|
+
"default": "false",
|
|
125
|
+
"description": "When set, prevents the tray from rendering visually-hidden dismiss helpers.\nUse this if your slotted content has custom keyboard-accessible dismiss functionality\nthat the auto-detection doesn't recognize.\n\nBy default, the tray automatically detects buttons in slotted content.",
|
|
126
|
+
"attribute": "has-keyboard-dismiss"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"kind": "field",
|
|
130
|
+
"name": "dismissHelper",
|
|
131
|
+
"type": {
|
|
132
|
+
"text": "TemplateResult"
|
|
133
|
+
},
|
|
134
|
+
"privacy": "protected",
|
|
135
|
+
"description": "Returns a visually hidden dismiss button for mobile screen reader accessibility.\nThis button is placed before and after tray content to allow mobile screen reader\nusers (particularly VoiceOver on iOS) to easily dismiss the overlay.",
|
|
136
|
+
"readonly": true
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"kind": "field",
|
|
140
|
+
"name": "needsDismissHelper",
|
|
141
|
+
"type": {
|
|
142
|
+
"text": "boolean"
|
|
143
|
+
},
|
|
144
|
+
"privacy": "private",
|
|
145
|
+
"default": "true",
|
|
146
|
+
"description": "Internal state tracking whether dismiss helpers are needed.\nAutomatically updated when slotted content changes."
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"kind": "method",
|
|
150
|
+
"name": "checkForDismissButtons",
|
|
151
|
+
"privacy": "private",
|
|
152
|
+
"return": {
|
|
153
|
+
"type": {
|
|
154
|
+
"text": "void"
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"description": "Check if slotted content has keyboard-accessible dismiss buttons.\nLooks for buttons in light DOM and checks for known components with built-in dismiss."
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"kind": "method",
|
|
161
|
+
"name": "handleSlotChange",
|
|
162
|
+
"privacy": "private",
|
|
163
|
+
"return": {
|
|
164
|
+
"type": {
|
|
165
|
+
"text": "void"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
109
169
|
{
|
|
110
170
|
"kind": "method",
|
|
111
171
|
"name": "dispatchClosed",
|
|
@@ -165,6 +225,15 @@
|
|
|
165
225
|
},
|
|
166
226
|
"default": "false",
|
|
167
227
|
"fieldName": "open"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"name": "has-keyboard-dismiss",
|
|
231
|
+
"type": {
|
|
232
|
+
"text": "boolean"
|
|
233
|
+
},
|
|
234
|
+
"default": "false",
|
|
235
|
+
"description": "When set, prevents the tray from rendering visually-hidden dismiss helpers.\nUse this if your slotted content has custom keyboard-accessible dismiss functionality\nthat the auto-detection doesn't recognize.\n\nBy default, the tray automatically detects buttons in slotted content.",
|
|
236
|
+
"fieldName": "hasKeyboardDismissButton"
|
|
168
237
|
}
|
|
169
238
|
],
|
|
170
239
|
"superclass": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spectrum-web-components/tray",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0-snapshot.20251106093044",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
"css"
|
|
65
65
|
],
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@spectrum-web-components/base": "1.
|
|
68
|
-
"@spectrum-web-components/modal": "1.
|
|
69
|
-
"@spectrum-web-components/reactive-controllers": "1.
|
|
70
|
-
"@spectrum-web-components/shared": "1.
|
|
71
|
-
"@spectrum-web-components/underlay": "1.
|
|
67
|
+
"@spectrum-web-components/base": "1.11.0-snapshot.20251106093044",
|
|
68
|
+
"@spectrum-web-components/modal": "1.11.0-snapshot.20251106093044",
|
|
69
|
+
"@spectrum-web-components/reactive-controllers": "1.11.0-snapshot.20251106093044",
|
|
70
|
+
"@spectrum-web-components/shared": "1.11.0-snapshot.20251106093044",
|
|
71
|
+
"@spectrum-web-components/underlay": "1.11.0-snapshot.20251106093044"
|
|
72
72
|
},
|
|
73
73
|
"types": "./src/index.d.ts",
|
|
74
74
|
"customElements": "custom-elements.json",
|
package/src/Tray.d.ts
CHANGED
|
@@ -26,13 +26,40 @@ export declare class Tray extends SpectrumElement {
|
|
|
26
26
|
private transitionPromise;
|
|
27
27
|
private resolveTransitionPromise;
|
|
28
28
|
private tray;
|
|
29
|
+
private contentSlot;
|
|
29
30
|
focus(): void;
|
|
30
31
|
private animating;
|
|
31
32
|
overlayWillCloseCallback(): boolean;
|
|
32
33
|
close(): void;
|
|
34
|
+
/**
|
|
35
|
+
* When set, prevents the tray from rendering visually-hidden dismiss helpers.
|
|
36
|
+
* Use this if your slotted content has custom keyboard-accessible dismiss functionality
|
|
37
|
+
* that the auto-detection doesn't recognize.
|
|
38
|
+
*
|
|
39
|
+
* By default, the tray automatically detects buttons in slotted content.
|
|
40
|
+
*/
|
|
41
|
+
hasKeyboardDismissButton: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Returns a visually hidden dismiss button for mobile screen reader accessibility.
|
|
44
|
+
* This button is placed before and after tray content to allow mobile screen reader
|
|
45
|
+
* users (particularly VoiceOver on iOS) to easily dismiss the overlay.
|
|
46
|
+
*/
|
|
47
|
+
protected get dismissHelper(): TemplateResult;
|
|
48
|
+
/**
|
|
49
|
+
* Internal state tracking whether dismiss helpers are needed.
|
|
50
|
+
* Automatically updated when slotted content changes.
|
|
51
|
+
*/
|
|
52
|
+
private needsDismissHelper;
|
|
53
|
+
/**
|
|
54
|
+
* Check if slotted content has keyboard-accessible dismiss buttons.
|
|
55
|
+
* Looks for buttons in light DOM and checks for known components with built-in dismiss.
|
|
56
|
+
*/
|
|
57
|
+
private checkForDismissButtons;
|
|
58
|
+
private handleSlotChange;
|
|
33
59
|
private dispatchClosed;
|
|
34
60
|
protected handleUnderlayTransitionend(): void;
|
|
35
61
|
protected handleTrayTransitionend(): void;
|
|
62
|
+
protected firstUpdated(changes: PropertyValues<this>): void;
|
|
36
63
|
protected update(changes: PropertyValues<this>): void;
|
|
37
64
|
protected render(): TemplateResult;
|
|
38
65
|
/**
|
package/src/Tray.dev.js
CHANGED
|
@@ -11,11 +11,13 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
11
11
|
};
|
|
12
12
|
import {
|
|
13
13
|
html,
|
|
14
|
+
nothing,
|
|
14
15
|
SpectrumElement
|
|
15
16
|
} from "@spectrum-web-components/base";
|
|
16
17
|
import {
|
|
17
18
|
property,
|
|
18
|
-
query
|
|
19
|
+
query,
|
|
20
|
+
state
|
|
19
21
|
} from "@spectrum-web-components/base/src/decorators.js";
|
|
20
22
|
import "@spectrum-web-components/underlay/sp-underlay.js";
|
|
21
23
|
import { firstFocusableIn } from "@spectrum-web-components/shared/src/first-focusable-in.js";
|
|
@@ -34,6 +36,8 @@ export class Tray extends SpectrumElement {
|
|
|
34
36
|
this.resolveTransitionPromise = () => {
|
|
35
37
|
};
|
|
36
38
|
this.animating = false;
|
|
39
|
+
this.hasKeyboardDismissButton = false;
|
|
40
|
+
this.needsDismissHelper = true;
|
|
37
41
|
}
|
|
38
42
|
static get styles() {
|
|
39
43
|
return [modalStyles, styles];
|
|
@@ -59,6 +63,57 @@ export class Tray extends SpectrumElement {
|
|
|
59
63
|
this.dispatchClosed();
|
|
60
64
|
}
|
|
61
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Returns a visually hidden dismiss button for mobile screen reader accessibility.
|
|
68
|
+
* This button is placed before and after tray content to allow mobile screen reader
|
|
69
|
+
* users (particularly VoiceOver on iOS) to easily dismiss the overlay.
|
|
70
|
+
*/
|
|
71
|
+
get dismissHelper() {
|
|
72
|
+
return html`
|
|
73
|
+
<div class="visually-hidden">
|
|
74
|
+
<button aria-label="Dismiss" @click=${this.close}></button>
|
|
75
|
+
</div>
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if slotted content has keyboard-accessible dismiss buttons.
|
|
80
|
+
* Looks for buttons in light DOM and checks for known components with built-in dismiss.
|
|
81
|
+
*/
|
|
82
|
+
checkForDismissButtons() {
|
|
83
|
+
if (!this.contentSlot) {
|
|
84
|
+
this.needsDismissHelper = true;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const slottedElements = this.contentSlot.assignedElements({
|
|
88
|
+
flatten: true
|
|
89
|
+
});
|
|
90
|
+
if (slottedElements.length === 0) {
|
|
91
|
+
this.needsDismissHelper = true;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const hasDismissButton = slottedElements.some((element) => {
|
|
95
|
+
if (element.tagName === "SP-BUTTON" || element.tagName === "SP-CLOSE-BUTTON" || element.tagName === "BUTTON") {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (element.tagName === "SP-DIALOG" && element.hasAttribute("dismissable")) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
if (element.tagName === "SP-DIALOG-WRAPPER" && element.hasAttribute("dismissable")) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
const buttons = element.querySelectorAll(
|
|
105
|
+
"sp-button, sp-close-button, button"
|
|
106
|
+
);
|
|
107
|
+
if (buttons.length > 0) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
});
|
|
112
|
+
this.needsDismissHelper = !hasDismissButton;
|
|
113
|
+
}
|
|
114
|
+
handleSlotChange() {
|
|
115
|
+
this.checkForDismissButtons();
|
|
116
|
+
}
|
|
62
117
|
dispatchClosed() {
|
|
63
118
|
this.dispatchEvent(
|
|
64
119
|
new Event("close", {
|
|
@@ -77,6 +132,10 @@ export class Tray extends SpectrumElement {
|
|
|
77
132
|
this.resolveTransitionPromise();
|
|
78
133
|
}
|
|
79
134
|
}
|
|
135
|
+
firstUpdated(changes) {
|
|
136
|
+
super.firstUpdated(changes);
|
|
137
|
+
this.checkForDismissButtons();
|
|
138
|
+
}
|
|
80
139
|
update(changes) {
|
|
81
140
|
if (changes.has("open") && changes.get("open") !== void 0 && this.prefersMotion.matches) {
|
|
82
141
|
this.animating = true;
|
|
@@ -101,7 +160,9 @@ export class Tray extends SpectrumElement {
|
|
|
101
160
|
tabindex="-1"
|
|
102
161
|
@transitionend=${this.handleTrayTransitionend}
|
|
103
162
|
>
|
|
104
|
-
|
|
163
|
+
${!this.hasKeyboardDismissButton && this.needsDismissHelper ? this.dismissHelper : nothing}
|
|
164
|
+
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
165
|
+
${!this.hasKeyboardDismissButton && this.needsDismissHelper ? this.dismissHelper : nothing}
|
|
105
166
|
</div>
|
|
106
167
|
`;
|
|
107
168
|
}
|
|
@@ -125,4 +186,13 @@ __decorateClass([
|
|
|
125
186
|
__decorateClass([
|
|
126
187
|
query(".tray")
|
|
127
188
|
], Tray.prototype, "tray", 2);
|
|
189
|
+
__decorateClass([
|
|
190
|
+
query("slot")
|
|
191
|
+
], Tray.prototype, "contentSlot", 2);
|
|
192
|
+
__decorateClass([
|
|
193
|
+
property({ type: Boolean, attribute: "has-keyboard-dismiss" })
|
|
194
|
+
], Tray.prototype, "hasKeyboardDismissButton", 2);
|
|
195
|
+
__decorateClass([
|
|
196
|
+
state()
|
|
197
|
+
], Tray.prototype, "needsDismissHelper", 2);
|
|
128
198
|
//# sourceMappingURL=Tray.dev.js.map
|
package/src/Tray.dev.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["Tray.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Copyright 2025 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n SpectrumElement,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport '@spectrum-web-components/underlay/sp-underlay.js';\nimport { firstFocusableIn } from '@spectrum-web-components/shared/src/first-focusable-in.js';\nimport { MatchMediaController } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';\n\nimport modalStyles from '@spectrum-web-components/modal/src/modal.css.js';\nimport styles from './tray.css.js';\n\n/**\n * @element sp-tray\n *\n * @slot - content to display within the Tray\n *\n * @fires close - Announces that the Tray has been closed.\n */\nexport class Tray extends SpectrumElement {\n public static override get styles(): CSSResultArray {\n return [modalStyles, styles];\n }\n\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n protected prefersMotion = new MatchMediaController(\n this,\n '(prefers-reduced-motion: no-preference)'\n );\n\n private transitionPromise = Promise.resolve();\n\n private resolveTransitionPromise = () => {};\n\n @query('.tray')\n private tray!: HTMLDivElement;\n\n public override focus(): void {\n const firstFocusable = firstFocusableIn(this);\n if (firstFocusable) {\n firstFocusable.focus();\n } else if (this.children.length === 1) {\n this.tray.focus();\n } else {\n super.focus();\n }\n }\n\n private animating = false;\n\n public overlayWillCloseCallback(): boolean {\n if (!this.open) return this.animating;\n this.close();\n return true;\n }\n\n public close(): void {\n this.open = false;\n if (!this.prefersMotion.matches) {\n this.dispatchClosed();\n }\n }\n\n private dispatchClosed(): void {\n this.dispatchEvent(\n new Event('close', {\n bubbles: true,\n })\n );\n }\n\n protected handleUnderlayTransitionend(): void {\n if (!this.open) {\n this.resolveTransitionPromise();\n this.dispatchClosed();\n }\n }\n\n protected handleTrayTransitionend(): void {\n if (this.open) {\n this.resolveTransitionPromise();\n }\n }\n\n protected override update(changes: PropertyValues<this>): void {\n if (\n changes.has('open') &&\n changes.get('open') !== undefined &&\n this.prefersMotion.matches\n ) {\n this.animating = true;\n this.transitionPromise = new Promise((res) => {\n this.resolveTransitionPromise = () => {\n this.animating = false;\n res();\n };\n });\n }\n super.update(changes);\n }\n\n protected override render(): TemplateResult {\n return html`\n <sp-underlay\n ?open=${this.open}\n @close=${this.close}\n @transitionend=${this.handleUnderlayTransitionend}\n ></sp-underlay>\n <div\n class=\"tray modal\"\n tabindex=\"-1\"\n @transitionend=${this.handleTrayTransitionend}\n >\n <slot></slot>\n </div>\n `;\n }\n\n /**\n * Bind the open/close transition into the update complete lifecycle so\n * that the overlay system can wait for it to be \"visibly ready\" before\n * attempting to throw focus into the content contained herein. Not\n * waiting for this can cause small amounts of page scroll to happen\n * while opening the Tray when focusable content is included: e.g. Menu\n * elements whose selected Menu Item is not the first Menu Item.\n */\n protected override async getUpdateComplete(): Promise<boolean> {\n const complete = (await super.getUpdateComplete()) as boolean;\n await this.transitionPromise;\n return complete;\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;AAYA;AAAA,EAEI;AAAA,EAEA;AAAA,OAEG;AACP;AAAA,EACI;AAAA,EACA;AAAA,OACG;AACP,OAAO;AACP,SAAS,wBAAwB;AACjC,SAAS,4BAA4B;AAErC,OAAO,iBAAiB;AACxB,OAAO,YAAY;AASZ,aAAM,aAAa,gBAAgB;AAAA,EAAnC;AAAA;AAMH,SAAO,OAAO;AAEd,SAAU,gBAAgB,IAAI;AAAA,MAC1B;AAAA,MACA;AAAA,IACJ;AAEA,SAAQ,oBAAoB,QAAQ,QAAQ;AAE5C,SAAQ,2BAA2B,MAAM;AAAA,IAAC;
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright 2025 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n nothing,\n PropertyValues,\n SpectrumElement,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport '@spectrum-web-components/underlay/sp-underlay.js';\nimport { firstFocusableIn } from '@spectrum-web-components/shared/src/first-focusable-in.js';\nimport { MatchMediaController } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';\n\nimport modalStyles from '@spectrum-web-components/modal/src/modal.css.js';\nimport styles from './tray.css.js';\n\n/**\n * @element sp-tray\n *\n * @slot - content to display within the Tray\n *\n * @fires close - Announces that the Tray has been closed.\n */\nexport class Tray extends SpectrumElement {\n public static override get styles(): CSSResultArray {\n return [modalStyles, styles];\n }\n\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n protected prefersMotion = new MatchMediaController(\n this,\n '(prefers-reduced-motion: no-preference)'\n );\n\n private transitionPromise = Promise.resolve();\n\n private resolveTransitionPromise = () => {};\n\n @query('.tray')\n private tray!: HTMLDivElement;\n\n @query('slot')\n private contentSlot!: HTMLSlotElement;\n\n public override focus(): void {\n const firstFocusable = firstFocusableIn(this);\n if (firstFocusable) {\n firstFocusable.focus();\n } else if (this.children.length === 1) {\n this.tray.focus();\n } else {\n super.focus();\n }\n }\n\n private animating = false;\n\n public overlayWillCloseCallback(): boolean {\n if (!this.open) return this.animating;\n this.close();\n return true;\n }\n\n public close(): void {\n this.open = false;\n if (!this.prefersMotion.matches) {\n this.dispatchClosed();\n }\n }\n\n /**\n * When set, prevents the tray from rendering visually-hidden dismiss helpers.\n * Use this if your slotted content has custom keyboard-accessible dismiss functionality\n * that the auto-detection doesn't recognize.\n *\n * By default, the tray automatically detects buttons in slotted content.\n */\n @property({ type: Boolean, attribute: 'has-keyboard-dismiss' })\n public hasKeyboardDismissButton = false;\n\n /**\n * Returns a visually hidden dismiss button for mobile screen reader accessibility.\n * This button is placed before and after tray content to allow mobile screen reader\n * users (particularly VoiceOver on iOS) to easily dismiss the overlay.\n */\n protected get dismissHelper(): TemplateResult {\n return html`\n <div class=\"visually-hidden\">\n <button aria-label=\"Dismiss\" @click=${this.close}></button>\n </div>\n `;\n }\n\n /**\n * Internal state tracking whether dismiss helpers are needed.\n * Automatically updated when slotted content changes.\n */\n @state()\n private needsDismissHelper = true;\n\n /**\n * Check if slotted content has keyboard-accessible dismiss buttons.\n * Looks for buttons in light DOM and checks for known components with built-in dismiss.\n */\n private checkForDismissButtons(): void {\n if (!this.contentSlot) {\n this.needsDismissHelper = true;\n return;\n }\n\n const slottedElements = this.contentSlot.assignedElements({\n flatten: true,\n });\n\n if (slottedElements.length === 0) {\n this.needsDismissHelper = true;\n return;\n }\n\n const hasDismissButton = slottedElements.some((element) => {\n // Check if element is a button itself\n if (\n element.tagName === 'SP-BUTTON' ||\n element.tagName === 'SP-CLOSE-BUTTON' ||\n element.tagName === 'BUTTON'\n ) {\n return true;\n }\n\n // Check for dismissable dialog (has built-in dismiss button in shadow DOM)\n if (\n element.tagName === 'SP-DIALOG' &&\n element.hasAttribute('dismissable')\n ) {\n return true;\n }\n\n // Check for dismissable dialog-wrapper\n if (\n element.tagName === 'SP-DIALOG-WRAPPER' &&\n element.hasAttribute('dismissable')\n ) {\n return true;\n }\n\n // Check for buttons in light DOM (won't see shadow DOM)\n const buttons = element.querySelectorAll(\n 'sp-button, sp-close-button, button'\n );\n if (buttons.length > 0) {\n return true;\n }\n\n return false;\n });\n\n this.needsDismissHelper = !hasDismissButton;\n }\n\n private handleSlotChange(): void {\n this.checkForDismissButtons();\n }\n\n private dispatchClosed(): void {\n this.dispatchEvent(\n new Event('close', {\n bubbles: true,\n })\n );\n }\n\n protected handleUnderlayTransitionend(): void {\n if (!this.open) {\n this.resolveTransitionPromise();\n this.dispatchClosed();\n }\n }\n\n protected handleTrayTransitionend(): void {\n if (this.open) {\n this.resolveTransitionPromise();\n }\n }\n\n protected override firstUpdated(changes: PropertyValues<this>): void {\n super.firstUpdated(changes);\n // Run initial button detection\n this.checkForDismissButtons();\n }\n\n protected override update(changes: PropertyValues<this>): void {\n if (\n changes.has('open') &&\n changes.get('open') !== undefined &&\n this.prefersMotion.matches\n ) {\n this.animating = true;\n this.transitionPromise = new Promise((res) => {\n this.resolveTransitionPromise = () => {\n this.animating = false;\n res();\n };\n });\n }\n super.update(changes);\n }\n\n protected override render(): TemplateResult {\n return html`\n <sp-underlay\n ?open=${this.open}\n @close=${this.close}\n @transitionend=${this.handleUnderlayTransitionend}\n ></sp-underlay>\n <div\n class=\"tray modal\"\n tabindex=\"-1\"\n @transitionend=${this.handleTrayTransitionend}\n >\n ${!this.hasKeyboardDismissButton && this.needsDismissHelper\n ? this.dismissHelper\n : nothing}\n <slot @slotchange=${this.handleSlotChange}></slot>\n ${!this.hasKeyboardDismissButton && this.needsDismissHelper\n ? this.dismissHelper\n : nothing}\n </div>\n `;\n }\n\n /**\n * Bind the open/close transition into the update complete lifecycle so\n * that the overlay system can wait for it to be \"visibly ready\" before\n * attempting to throw focus into the content contained herein. Not\n * waiting for this can cause small amounts of page scroll to happen\n * while opening the Tray when focusable content is included: e.g. Menu\n * elements whose selected Menu Item is not the first Menu Item.\n */\n protected override async getUpdateComplete(): Promise<boolean> {\n const complete = (await super.getUpdateComplete()) as boolean;\n await this.transitionPromise;\n return complete;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/src/Tray.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var h=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var i=(n,r,e,s)=>{for(var t=s>1?void 0:s?m(r,e):r,o=n.length-1,a;o>=0;o--)(a=n[o])&&(t=(s?a(r,e,t):a(t))||t);return s&&t&&h(r,e,t),t};import{html as l,nothing as d,SpectrumElement as c}from"@spectrum-web-components/base";import{property as p,query as u,state as f}from"@spectrum-web-components/base/src/decorators.js";import"@spectrum-web-components/underlay/sp-underlay.js";import{firstFocusableIn as v}from"@spectrum-web-components/shared/src/first-focusable-in.js";import{MatchMediaController as b}from"@spectrum-web-components/reactive-controllers/src/MatchMedia.js";import y from"@spectrum-web-components/modal/src/modal.css.js";import g from"./tray.css.js";export class Tray extends c{constructor(){super(...arguments);this.open=!1;this.prefersMotion=new b(this,"(prefers-reduced-motion: no-preference)");this.transitionPromise=Promise.resolve();this.resolveTransitionPromise=()=>{};this.animating=!1;this.hasKeyboardDismissButton=!1;this.needsDismissHelper=!0}static get styles(){return[y,g]}focus(){const e=v(this);e?e.focus():this.children.length===1?this.tray.focus():super.focus()}overlayWillCloseCallback(){return this.open?(this.close(),!0):this.animating}close(){this.open=!1,this.prefersMotion.matches||this.dispatchClosed()}get dismissHelper(){return l`
|
|
2
|
+
<div class="visually-hidden">
|
|
3
|
+
<button aria-label="Dismiss" @click=${this.close}></button>
|
|
4
|
+
</div>
|
|
5
|
+
`}checkForDismissButtons(){if(!this.contentSlot){this.needsDismissHelper=!0;return}const e=this.contentSlot.assignedElements({flatten:!0});if(e.length===0){this.needsDismissHelper=!0;return}const s=e.some(t=>!!(t.tagName==="SP-BUTTON"||t.tagName==="SP-CLOSE-BUTTON"||t.tagName==="BUTTON"||t.tagName==="SP-DIALOG"&&t.hasAttribute("dismissable")||t.tagName==="SP-DIALOG-WRAPPER"&&t.hasAttribute("dismissable")||t.querySelectorAll("sp-button, sp-close-button, button").length>0));this.needsDismissHelper=!s}handleSlotChange(){this.checkForDismissButtons()}dispatchClosed(){this.dispatchEvent(new Event("close",{bubbles:!0}))}handleUnderlayTransitionend(){this.open||(this.resolveTransitionPromise(),this.dispatchClosed())}handleTrayTransitionend(){this.open&&this.resolveTransitionPromise()}firstUpdated(e){super.firstUpdated(e),this.checkForDismissButtons()}update(e){e.has("open")&&e.get("open")!==void 0&&this.prefersMotion.matches&&(this.animating=!0,this.transitionPromise=new Promise(s=>{this.resolveTransitionPromise=()=>{this.animating=!1,s()}})),super.update(e)}render(){return l`
|
|
2
6
|
<sp-underlay
|
|
3
7
|
?open=${this.open}
|
|
4
8
|
@close=${this.close}
|
|
@@ -9,7 +13,9 @@
|
|
|
9
13
|
tabindex="-1"
|
|
10
14
|
@transitionend=${this.handleTrayTransitionend}
|
|
11
15
|
>
|
|
12
|
-
|
|
16
|
+
${!this.hasKeyboardDismissButton&&this.needsDismissHelper?this.dismissHelper:d}
|
|
17
|
+
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
18
|
+
${!this.hasKeyboardDismissButton&&this.needsDismissHelper?this.dismissHelper:d}
|
|
13
19
|
</div>
|
|
14
|
-
`}async getUpdateComplete(){const e=await super.getUpdateComplete();return await this.transitionPromise,e}}
|
|
20
|
+
`}async getUpdateComplete(){const e=await super.getUpdateComplete();return await this.transitionPromise,e}}i([p({type:Boolean,reflect:!0})],Tray.prototype,"open",2),i([u(".tray")],Tray.prototype,"tray",2),i([u("slot")],Tray.prototype,"contentSlot",2),i([p({type:Boolean,attribute:"has-keyboard-dismiss"})],Tray.prototype,"hasKeyboardDismissButton",2),i([f()],Tray.prototype,"needsDismissHelper",2);
|
|
15
21
|
//# sourceMappingURL=Tray.js.map
|
package/src/Tray.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["Tray.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Copyright 2025 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n SpectrumElement,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport '@spectrum-web-components/underlay/sp-underlay.js';\nimport { firstFocusableIn } from '@spectrum-web-components/shared/src/first-focusable-in.js';\nimport { MatchMediaController } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';\n\nimport modalStyles from '@spectrum-web-components/modal/src/modal.css.js';\nimport styles from './tray.css.js';\n\n/**\n * @element sp-tray\n *\n * @slot - content to display within the Tray\n *\n * @fires close - Announces that the Tray has been closed.\n */\nexport class Tray extends SpectrumElement {\n public static override get styles(): CSSResultArray {\n return [modalStyles, styles];\n }\n\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n protected prefersMotion = new MatchMediaController(\n this,\n '(prefers-reduced-motion: no-preference)'\n );\n\n private transitionPromise = Promise.resolve();\n\n private resolveTransitionPromise = () => {};\n\n @query('.tray')\n private tray!: HTMLDivElement;\n\n public override focus(): void {\n const firstFocusable = firstFocusableIn(this);\n if (firstFocusable) {\n firstFocusable.focus();\n } else if (this.children.length === 1) {\n this.tray.focus();\n } else {\n super.focus();\n }\n }\n\n private animating = false;\n\n public overlayWillCloseCallback(): boolean {\n if (!this.open) return this.animating;\n this.close();\n return true;\n }\n\n public close(): void {\n this.open = false;\n if (!this.prefersMotion.matches) {\n this.dispatchClosed();\n }\n }\n\n private dispatchClosed(): void {\n this.dispatchEvent(\n new Event('close', {\n bubbles: true,\n })\n );\n }\n\n protected handleUnderlayTransitionend(): void {\n if (!this.open) {\n this.resolveTransitionPromise();\n this.dispatchClosed();\n }\n }\n\n protected handleTrayTransitionend(): void {\n if (this.open) {\n this.resolveTransitionPromise();\n }\n }\n\n protected override update(changes: PropertyValues<this>): void {\n if (\n changes.has('open') &&\n changes.get('open') !== undefined &&\n this.prefersMotion.matches\n ) {\n this.animating = true;\n this.transitionPromise = new Promise((res) => {\n this.resolveTransitionPromise = () => {\n this.animating = false;\n res();\n };\n });\n }\n super.update(changes);\n }\n\n protected override render(): TemplateResult {\n return html`\n <sp-underlay\n ?open=${this.open}\n @close=${this.close}\n @transitionend=${this.handleUnderlayTransitionend}\n ></sp-underlay>\n <div\n class=\"tray modal\"\n tabindex=\"-1\"\n @transitionend=${this.handleTrayTransitionend}\n >\n <slot></slot>\n </div>\n `;\n }\n\n /**\n * Bind the open/close transition into the update complete lifecycle so\n * that the overlay system can wait for it to be \"visibly ready\" before\n * attempting to throw focus into the content contained herein. Not\n * waiting for this can cause small amounts of page scroll to happen\n * while opening the Tray when focusable content is included: e.g. Menu\n * elements whose selected Menu Item is not the first Menu Item.\n */\n protected override async getUpdateComplete(): Promise<boolean> {\n const complete = (await super.getUpdateComplete()) as boolean;\n await this.transitionPromise;\n return complete;\n }\n}\n"],
|
|
5
|
-
"mappings": "qNAYA,OAEI,QAAAA,EAEA,mBAAAC,MAEG,gCACP,OACI,YAAAC,EACA,SAAAC,MACG,kDACP,MAAO,mDACP,OAAS,oBAAAC,MAAwB,4DACjC,OAAS,wBAAAC,MAA4B,kEAErC,OAAOC,MAAiB,kDACxB,OAAOC,MAAY,gBASZ,aAAM,
|
|
6
|
-
"names": ["html", "SpectrumElement", "property", "query", "firstFocusableIn", "MatchMediaController", "modalStyles", "styles", "firstFocusable", "changes", "res", "complete", "__decorateClass"]
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright 2025 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n nothing,\n PropertyValues,\n SpectrumElement,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport '@spectrum-web-components/underlay/sp-underlay.js';\nimport { firstFocusableIn } from '@spectrum-web-components/shared/src/first-focusable-in.js';\nimport { MatchMediaController } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';\n\nimport modalStyles from '@spectrum-web-components/modal/src/modal.css.js';\nimport styles from './tray.css.js';\n\n/**\n * @element sp-tray\n *\n * @slot - content to display within the Tray\n *\n * @fires close - Announces that the Tray has been closed.\n */\nexport class Tray extends SpectrumElement {\n public static override get styles(): CSSResultArray {\n return [modalStyles, styles];\n }\n\n @property({ type: Boolean, reflect: true })\n public open = false;\n\n protected prefersMotion = new MatchMediaController(\n this,\n '(prefers-reduced-motion: no-preference)'\n );\n\n private transitionPromise = Promise.resolve();\n\n private resolveTransitionPromise = () => {};\n\n @query('.tray')\n private tray!: HTMLDivElement;\n\n @query('slot')\n private contentSlot!: HTMLSlotElement;\n\n public override focus(): void {\n const firstFocusable = firstFocusableIn(this);\n if (firstFocusable) {\n firstFocusable.focus();\n } else if (this.children.length === 1) {\n this.tray.focus();\n } else {\n super.focus();\n }\n }\n\n private animating = false;\n\n public overlayWillCloseCallback(): boolean {\n if (!this.open) return this.animating;\n this.close();\n return true;\n }\n\n public close(): void {\n this.open = false;\n if (!this.prefersMotion.matches) {\n this.dispatchClosed();\n }\n }\n\n /**\n * When set, prevents the tray from rendering visually-hidden dismiss helpers.\n * Use this if your slotted content has custom keyboard-accessible dismiss functionality\n * that the auto-detection doesn't recognize.\n *\n * By default, the tray automatically detects buttons in slotted content.\n */\n @property({ type: Boolean, attribute: 'has-keyboard-dismiss' })\n public hasKeyboardDismissButton = false;\n\n /**\n * Returns a visually hidden dismiss button for mobile screen reader accessibility.\n * This button is placed before and after tray content to allow mobile screen reader\n * users (particularly VoiceOver on iOS) to easily dismiss the overlay.\n */\n protected get dismissHelper(): TemplateResult {\n return html`\n <div class=\"visually-hidden\">\n <button aria-label=\"Dismiss\" @click=${this.close}></button>\n </div>\n `;\n }\n\n /**\n * Internal state tracking whether dismiss helpers are needed.\n * Automatically updated when slotted content changes.\n */\n @state()\n private needsDismissHelper = true;\n\n /**\n * Check if slotted content has keyboard-accessible dismiss buttons.\n * Looks for buttons in light DOM and checks for known components with built-in dismiss.\n */\n private checkForDismissButtons(): void {\n if (!this.contentSlot) {\n this.needsDismissHelper = true;\n return;\n }\n\n const slottedElements = this.contentSlot.assignedElements({\n flatten: true,\n });\n\n if (slottedElements.length === 0) {\n this.needsDismissHelper = true;\n return;\n }\n\n const hasDismissButton = slottedElements.some((element) => {\n // Check if element is a button itself\n if (\n element.tagName === 'SP-BUTTON' ||\n element.tagName === 'SP-CLOSE-BUTTON' ||\n element.tagName === 'BUTTON'\n ) {\n return true;\n }\n\n // Check for dismissable dialog (has built-in dismiss button in shadow DOM)\n if (\n element.tagName === 'SP-DIALOG' &&\n element.hasAttribute('dismissable')\n ) {\n return true;\n }\n\n // Check for dismissable dialog-wrapper\n if (\n element.tagName === 'SP-DIALOG-WRAPPER' &&\n element.hasAttribute('dismissable')\n ) {\n return true;\n }\n\n // Check for buttons in light DOM (won't see shadow DOM)\n const buttons = element.querySelectorAll(\n 'sp-button, sp-close-button, button'\n );\n if (buttons.length > 0) {\n return true;\n }\n\n return false;\n });\n\n this.needsDismissHelper = !hasDismissButton;\n }\n\n private handleSlotChange(): void {\n this.checkForDismissButtons();\n }\n\n private dispatchClosed(): void {\n this.dispatchEvent(\n new Event('close', {\n bubbles: true,\n })\n );\n }\n\n protected handleUnderlayTransitionend(): void {\n if (!this.open) {\n this.resolveTransitionPromise();\n this.dispatchClosed();\n }\n }\n\n protected handleTrayTransitionend(): void {\n if (this.open) {\n this.resolveTransitionPromise();\n }\n }\n\n protected override firstUpdated(changes: PropertyValues<this>): void {\n super.firstUpdated(changes);\n // Run initial button detection\n this.checkForDismissButtons();\n }\n\n protected override update(changes: PropertyValues<this>): void {\n if (\n changes.has('open') &&\n changes.get('open') !== undefined &&\n this.prefersMotion.matches\n ) {\n this.animating = true;\n this.transitionPromise = new Promise((res) => {\n this.resolveTransitionPromise = () => {\n this.animating = false;\n res();\n };\n });\n }\n super.update(changes);\n }\n\n protected override render(): TemplateResult {\n return html`\n <sp-underlay\n ?open=${this.open}\n @close=${this.close}\n @transitionend=${this.handleUnderlayTransitionend}\n ></sp-underlay>\n <div\n class=\"tray modal\"\n tabindex=\"-1\"\n @transitionend=${this.handleTrayTransitionend}\n >\n ${!this.hasKeyboardDismissButton && this.needsDismissHelper\n ? this.dismissHelper\n : nothing}\n <slot @slotchange=${this.handleSlotChange}></slot>\n ${!this.hasKeyboardDismissButton && this.needsDismissHelper\n ? this.dismissHelper\n : nothing}\n </div>\n `;\n }\n\n /**\n * Bind the open/close transition into the update complete lifecycle so\n * that the overlay system can wait for it to be \"visibly ready\" before\n * attempting to throw focus into the content contained herein. Not\n * waiting for this can cause small amounts of page scroll to happen\n * while opening the Tray when focusable content is included: e.g. Menu\n * elements whose selected Menu Item is not the first Menu Item.\n */\n protected override async getUpdateComplete(): Promise<boolean> {\n const complete = (await super.getUpdateComplete()) as boolean;\n await this.transitionPromise;\n return complete;\n }\n}\n"],
|
|
5
|
+
"mappings": "qNAYA,OAEI,QAAAA,EACA,WAAAC,EAEA,mBAAAC,MAEG,gCACP,OACI,YAAAC,EACA,SAAAC,EACA,SAAAC,MACG,kDACP,MAAO,mDACP,OAAS,oBAAAC,MAAwB,4DACjC,OAAS,wBAAAC,MAA4B,kEAErC,OAAOC,MAAiB,kDACxB,OAAOC,MAAY,gBASZ,aAAM,aAAaP,CAAgB,CAAnC,kCAMH,KAAO,KAAO,GAEd,KAAU,cAAgB,IAAIK,EAC1B,KACA,yCACJ,EAEA,KAAQ,kBAAoB,QAAQ,QAAQ,EAE5C,KAAQ,yBAA2B,IAAM,CAAC,EAmB1C,KAAQ,UAAY,GAuBpB,KAAO,yBAA2B,GAoBlC,KAAQ,mBAAqB,GA5E7B,WAA2B,QAAyB,CAChD,MAAO,CAACC,EAAaC,CAAM,CAC/B,CAoBgB,OAAc,CAC1B,MAAMC,EAAiBJ,EAAiB,IAAI,EACxCI,EACAA,EAAe,MAAM,EACd,KAAK,SAAS,SAAW,EAChC,KAAK,KAAK,MAAM,EAEhB,MAAM,MAAM,CAEpB,CAIO,0BAAoC,CACvC,OAAK,KAAK,MACV,KAAK,MAAM,EACJ,IAFgB,KAAK,SAGhC,CAEO,OAAc,CACjB,KAAK,KAAO,GACP,KAAK,cAAc,SACpB,KAAK,eAAe,CAE5B,CAiBA,IAAc,eAAgC,CAC1C,OAAOV;AAAA;AAAA,sDAEuC,KAAK,KAAK;AAAA;AAAA,SAG5D,CAaQ,wBAA+B,CACnC,GAAI,CAAC,KAAK,YAAa,CACnB,KAAK,mBAAqB,GAC1B,MACJ,CAEA,MAAMW,EAAkB,KAAK,YAAY,iBAAiB,CACtD,QAAS,EACb,CAAC,EAED,GAAIA,EAAgB,SAAW,EAAG,CAC9B,KAAK,mBAAqB,GAC1B,MACJ,CAEA,MAAMC,EAAmBD,EAAgB,KAAME,GAGvC,GAAAA,EAAQ,UAAY,aACpBA,EAAQ,UAAY,mBACpBA,EAAQ,UAAY,UAOpBA,EAAQ,UAAY,aACpBA,EAAQ,aAAa,aAAa,GAOlCA,EAAQ,UAAY,qBACpBA,EAAQ,aAAa,aAAa,GAMtBA,EAAQ,iBACpB,oCACJ,EACY,OAAS,EAKxB,EAED,KAAK,mBAAqB,CAACD,CAC/B,CAEQ,kBAAyB,CAC7B,KAAK,uBAAuB,CAChC,CAEQ,gBAAuB,CAC3B,KAAK,cACD,IAAI,MAAM,QAAS,CACf,QAAS,EACb,CAAC,CACL,CACJ,CAEU,6BAAoC,CACrC,KAAK,OACN,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EAE5B,CAEU,yBAAgC,CAClC,KAAK,MACL,KAAK,yBAAyB,CAEtC,CAEmB,aAAaE,EAAqC,CACjE,MAAM,aAAaA,CAAO,EAE1B,KAAK,uBAAuB,CAChC,CAEmB,OAAOA,EAAqC,CAEvDA,EAAQ,IAAI,MAAM,GAClBA,EAAQ,IAAI,MAAM,IAAM,QACxB,KAAK,cAAc,UAEnB,KAAK,UAAY,GACjB,KAAK,kBAAoB,IAAI,QAASC,GAAQ,CAC1C,KAAK,yBAA2B,IAAM,CAClC,KAAK,UAAY,GACjBA,EAAI,CACR,CACJ,CAAC,GAEL,MAAM,OAAOD,CAAO,CACxB,CAEmB,QAAyB,CACxC,OAAOd;AAAA;AAAA,wBAES,KAAK,IAAI;AAAA,yBACR,KAAK,KAAK;AAAA,iCACF,KAAK,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA,iCAKhC,KAAK,uBAAuB;AAAA;AAAA,kBAE3C,CAAC,KAAK,0BAA4B,KAAK,mBACnC,KAAK,cACLC,CAAO;AAAA,oCACO,KAAK,gBAAgB;AAAA,kBACvC,CAAC,KAAK,0BAA4B,KAAK,mBACnC,KAAK,cACLA,CAAO;AAAA;AAAA,SAGzB,CAUA,MAAyB,mBAAsC,CAC3D,MAAMe,EAAY,MAAM,MAAM,kBAAkB,EAChD,aAAM,KAAK,kBACJA,CACX,CACJ,CAxNWC,EAAA,CADNd,EAAS,CAAE,KAAM,QAAS,QAAS,EAAK,CAAC,GALjC,KAMF,oBAYCc,EAAA,CADPb,EAAM,OAAO,GAjBL,KAkBD,oBAGAa,EAAA,CADPb,EAAM,MAAM,GApBJ,KAqBD,2BAoCDa,EAAA,CADNd,EAAS,CAAE,KAAM,QAAS,UAAW,sBAAuB,CAAC,GAxDrD,KAyDF,wCAoBCc,EAAA,CADPZ,EAAM,GA5EE,KA6ED",
|
|
6
|
+
"names": ["html", "nothing", "SpectrumElement", "property", "query", "state", "firstFocusableIn", "MatchMediaController", "modalStyles", "styles", "firstFocusable", "slottedElements", "hasDismissButton", "element", "changes", "res", "complete", "__decorateClass"]
|
|
7
7
|
}
|
package/src/tray.css.dev.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
import { css } from "@spectrum-web-components/base";
|
|
3
3
|
const styles = css`
|
|
4
|
-
:host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}
|
|
4
|
+
:host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}.visually-hidden,::slotted(.visually-hidden){clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:0 -1px -1px 0;padding:0;position:absolute;overflow:hidden}
|
|
5
5
|
`;
|
|
6
6
|
export default styles;
|
|
7
7
|
//# sourceMappingURL=tray.css.dev.js.map
|
package/src/tray.css.dev.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["tray.css.ts"],
|
|
4
|
-
"sourcesContent": ["import { css } from '@spectrum-web-components/base';\nconst styles = css`\n :host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}
|
|
4
|
+
"sourcesContent": ["import { css } from '@spectrum-web-components/base';\nconst styles = css`\n :host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}.visually-hidden,::slotted(.visually-hidden){clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:0 -1px -1px 0;padding:0;position:absolute;overflow:hidden}\n`;\nexport default styles;"],
|
|
5
5
|
"mappings": ";AAAA,SAAS,WAAW;AACpB,MAAM,SAAS;AAAA;AAAA;AAGf,eAAe;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/src/tray.css.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
"use strict";import{css as a}from"@spectrum-web-components/base";const r=a`
|
|
2
|
-
:host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}
|
|
2
|
+
:host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}.visually-hidden,::slotted(.visually-hidden){clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:0 -1px -1px 0;padding:0;position:absolute;overflow:hidden}
|
|
3
3
|
`;export default r;
|
|
4
4
|
//# sourceMappingURL=tray.css.js.map
|
package/src/tray.css.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["tray.css.ts"],
|
|
4
|
-
"sourcesContent": ["import { css } from '@spectrum-web-components/base';\nconst styles = css`\n :host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}
|
|
4
|
+
"sourcesContent": ["import { css } from '@spectrum-web-components/base';\nconst styles = css`\n :host{justify-content:center;inline-size:100%;display:flex;position:fixed;inset-block-end:0;inset-inline-start:0}.tray{--spectrum-tray-max-inline-size:var(--mod-tray-max-inline-size,375px);--spectrum-tray-spacing-edge-to-tray-safe-zone:var(--mod-tray-spacing-edge-to-tray-safe-zone,64px);--spectrum-tray-entry-animation-delay:var(--mod-tray-entry-animation-delay,.16s);--spectrum-tray-entry-animation-duration:var(--mod-tray-entry-animation-duration,var(--spectrum-animation-duration-500));--spectrum-tray-exit-animation-delay:var(--mod-tray-exit-animation-delay,0s);--spectrum-tray-exit-animation-duration:var(--mod-tray-exit-animation-duration,var(--spectrum-animation-duration-100));--spectrum-tray-corner-radius:var(--mod-tray-corner-radius,var(--spectrum-corner-radius-100));--spectrum-tray-background-color:var(--highcontrast-tray-background-color,var(--mod-tray-background-color,var(--spectrum-background-layer-2-color)));--mod-modal-max-width:100%;max-block-size:calc(100vh - 64px);inline-size:100%;max-inline-size:100%;max-block-size:calc(100vh - var(--spectrum-tray-spacing-edge-to-tray-safe-zone));box-sizing:border-box;border-radius:0;border-radius:var(--mod-tray-corner-radius-portrait,0)var(--mod-tray-corner-radius-portrait,0)0 0;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s,visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)0s;transition:opacity var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay),visibility var(--spectrum-tray-exit-animation-duration)linear calc(var(--spectrum-tray-exit-animation-delay) + var(--spectrum-tray-exit-animation-duration)),transform var(--spectrum-tray-exit-animation-duration)cubic-bezier(.5,0,1,1)var(--spectrum-tray-exit-animation-delay);background-color:var(--spectrum-tray-background-color);outline:none;margin-block-start:var(--spectrum-tray-spacing-edge-to-tray-safe-zone);padding-block-start:var(--mod-tray-top-to-content-area,var(--spectrum-tray-top-to-content-area));padding-block-end:var(--mod-tray-bottom-to-content-area,var(--spectrum-tray-top-to-content-area));overflow:auto;transform:translateY(100%)}:host([open]) .tray{transition:transform var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay),opacity var(--spectrum-tray-entry-animation-duration)cubic-bezier(0,0,.4,1)var(--spectrum-tray-entry-animation-delay);transform:translateY(0)}@media screen and (orientation:landscape){.tray{max-inline-size:var(--spectrum-tray-max-inline-size);border-start-start-radius:var(--spectrum-tray-corner-radius);border-start-end-radius:var(--spectrum-tray-corner-radius)}}@media (forced-colors:active){.tray{--highcontrast-tray-background-color:Canvas;border:solid}.tray ::slotted(*){border:none}}:host{align-items:flex-end;max-height:100dvh;position:fixed!important}sp-underlay{touch-action:none}.tray{overscroll-behavior:contain;display:inline-flex}.visually-hidden,::slotted(.visually-hidden){clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:0 -1px -1px 0;padding:0;position:absolute;overflow:hidden}\n`;\nexport default styles;"],
|
|
5
5
|
"mappings": "aAAA,OAAS,OAAAA,MAAW,gCACpB,MAAMC,EAASD;AAAA;AAAA,EAGf,eAAeC",
|
|
6
6
|
"names": ["css", "styles"]
|
|
7
7
|
}
|