@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 CHANGED
@@ -7,19 +7,19 @@
7
7
  [![See it on NPM!](https://img.shields.io/npm/v/@spectrum-web-components/tray?style=for-the-badge)](https://www.npmjs.com/package/@spectrum-web-components/tray)
8
8
  [![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/@spectrum-web-components/tray?style=for-the-badge)](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>
@@ -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.10.0",
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.10.0",
68
- "@spectrum-web-components/modal": "1.10.0",
69
- "@spectrum-web-components/reactive-controllers": "1.10.0",
70
- "@spectrum-web-components/shared": "1.10.0",
71
- "@spectrum-web-components/underlay": "1.10.0"
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
- <slot></slot>
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
@@ -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;AAgB1C,SAAQ,YAAY;AAAA;AAAA,EA9BpB,WAA2B,SAAyB;AAChD,WAAO,CAAC,aAAa,MAAM;AAAA,EAC/B;AAAA,EAiBgB,QAAc;AAC1B,UAAM,iBAAiB,iBAAiB,IAAI;AAC5C,QAAI,gBAAgB;AAChB,qBAAe,MAAM;AAAA,IACzB,WAAW,KAAK,SAAS,WAAW,GAAG;AACnC,WAAK,KAAK,MAAM;AAAA,IACpB,OAAO;AACH,YAAM,MAAM;AAAA,IAChB;AAAA,EACJ;AAAA,EAIO,2BAAoC;AACvC,QAAI,CAAC,KAAK,KAAM,QAAO,KAAK;AAC5B,SAAK,MAAM;AACX,WAAO;AAAA,EACX;AAAA,EAEO,QAAc;AACjB,SAAK,OAAO;AACZ,QAAI,CAAC,KAAK,cAAc,SAAS;AAC7B,WAAK,eAAe;AAAA,IACxB;AAAA,EACJ;AAAA,EAEQ,iBAAuB;AAC3B,SAAK;AAAA,MACD,IAAI,MAAM,SAAS;AAAA,QACf,SAAS;AAAA,MACb,CAAC;AAAA,IACL;AAAA,EACJ;AAAA,EAEU,8BAAoC;AAC1C,QAAI,CAAC,KAAK,MAAM;AACZ,WAAK,yBAAyB;AAC9B,WAAK,eAAe;AAAA,IACxB;AAAA,EACJ;AAAA,EAEU,0BAAgC;AACtC,QAAI,KAAK,MAAM;AACX,WAAK,yBAAyB;AAAA,IAClC;AAAA,EACJ;AAAA,EAEmB,OAAO,SAAqC;AAC3D,QACI,QAAQ,IAAI,MAAM,KAClB,QAAQ,IAAI,MAAM,MAAM,UACxB,KAAK,cAAc,SACrB;AACE,WAAK,YAAY;AACjB,WAAK,oBAAoB,IAAI,QAAQ,CAAC,QAAQ;AAC1C,aAAK,2BAA2B,MAAM;AAClC,eAAK,YAAY;AACjB,cAAI;AAAA,QACR;AAAA,MACJ,CAAC;AAAA,IACL;AACA,UAAM,OAAO,OAAO;AAAA,EACxB;AAAA,EAEmB,SAAyB;AACxC,WAAO;AAAA;AAAA,wBAES,KAAK,IAAI;AAAA,yBACR,KAAK,KAAK;AAAA,iCACF,KAAK,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA,iCAKhC,KAAK,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAyB,oBAAsC;AAC3D,UAAM,WAAY,MAAM,MAAM,kBAAkB;AAChD,UAAM,KAAK;AACX,WAAO;AAAA,EACX;AACJ;AA5GW;AAAA,EADN,SAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GALjC,KAMF;AAYC;AAAA,EADP,MAAM,OAAO;AAAA,GAjBL,KAkBD;",
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 l=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var a=(s,r,e,i)=>{for(var t=i>1?void 0:i?p(r,e):r,o=s.length-1,n;o>=0;o--)(n=s[o])&&(t=(i?n(r,e,t):n(t))||t);return i&&t&&l(r,e,t),t};import{html as d,SpectrumElement as m}from"@spectrum-web-components/base";import{property as c,query as h}from"@spectrum-web-components/base/src/decorators.js";import"@spectrum-web-components/underlay/sp-underlay.js";import{firstFocusableIn as u}from"@spectrum-web-components/shared/src/first-focusable-in.js";import{MatchMediaController as f}from"@spectrum-web-components/reactive-controllers/src/MatchMedia.js";import v from"@spectrum-web-components/modal/src/modal.css.js";import y from"./tray.css.js";export class Tray extends m{constructor(){super(...arguments);this.open=!1;this.prefersMotion=new f(this,"(prefers-reduced-motion: no-preference)");this.transitionPromise=Promise.resolve();this.resolveTransitionPromise=()=>{};this.animating=!1}static get styles(){return[v,y]}focus(){const e=u(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()}dispatchClosed(){this.dispatchEvent(new Event("close",{bubbles:!0}))}handleUnderlayTransitionend(){this.open||(this.resolveTransitionPromise(),this.dispatchClosed())}handleTrayTransitionend(){this.open&&this.resolveTransitionPromise()}update(e){e.has("open")&&e.get("open")!==void 0&&this.prefersMotion.matches&&(this.animating=!0,this.transitionPromise=new Promise(i=>{this.resolveTransitionPromise=()=>{this.animating=!1,i()}})),super.update(e)}render(){return d`
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
- <slot></slot>
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}}a([c({type:Boolean,reflect:!0})],Tray.prototype,"open",2),a([h(".tray")],Tray.prototype,"tray",2);
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,aAAaN,CAAgB,CAAnC,kCAMH,KAAO,KAAO,GAEd,KAAU,cAAgB,IAAII,EAC1B,KACA,yCACJ,EAEA,KAAQ,kBAAoB,QAAQ,QAAQ,EAE5C,KAAQ,yBAA2B,IAAM,CAAC,EAgB1C,KAAQ,UAAY,GA9BpB,WAA2B,QAAyB,CAChD,MAAO,CAACC,EAAaC,CAAM,CAC/B,CAiBgB,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,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,OAAOC,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,OAAOT;AAAA;AAAA,wBAES,KAAK,IAAI;AAAA,yBACR,KAAK,KAAK;AAAA,iCACF,KAAK,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA,iCAKhC,KAAK,uBAAuB;AAAA;AAAA;AAAA;AAAA,SAKzD,CAUA,MAAyB,mBAAsC,CAC3D,MAAMW,EAAY,MAAM,MAAM,kBAAkB,EAChD,aAAM,KAAK,kBACJA,CACX,CACJ,CA5GWC,EAAA,CADNV,EAAS,CAAE,KAAM,QAAS,QAAS,EAAK,CAAC,GALjC,KAMF,oBAYCU,EAAA,CADPT,EAAM,OAAO,GAjBL,KAkBD",
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": "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",
6
+ "names": ["html", "nothing", "SpectrumElement", "property", "query", "state", "firstFocusableIn", "MatchMediaController", "modalStyles", "styles", "firstFocusable", "slottedElements", "hasDismissButton", "element", "changes", "res", "complete", "__decorateClass"]
7
7
  }
@@ -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}::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}
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
@@ -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}::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;"],
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}::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}
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
@@ -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}::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;"],
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
  }