• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

adobe / spectrum-web-components / 18327331653

07 Oct 2025 09:59PM UTC coverage: 97.929% (-0.06%) from 97.984%
18327331653

Pull #5792

github

web-flow
Merge 8914ce201 into 7d23140c2
Pull Request #5792: remove animations from some components

5338 of 5625 branches covered (94.9%)

Branch coverage included in aggregate %.

34050 of 34596 relevant lines covered (98.42%)

649.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.21
/packages/tray/src/Tray.ts
1
/**
9✔
2
 * Copyright 2025 Adobe. All rights reserved.
9✔
3
 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
9✔
4
 * you may not use this file except in compliance with the License. You may obtain a copy
9✔
5
 * of the License at http://www.apache.org/licenses/LICENSE-2.0
9✔
6
 *
9✔
7
 * Unless required by applicable law or agreed to in writing, software distributed under
9✔
8
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9✔
9
 * OF ANY KIND, either express or implied. See the License for the specific language
9✔
10
 * governing permissions and limitations under the License.
9✔
11
 */
9✔
12

9✔
13
import {
9✔
14
    CSSResultArray,
9✔
15
    html,
9✔
16
    PropertyValues,
9✔
17
    SpectrumElement,
9✔
18
    TemplateResult,
9✔
19
} from '@spectrum-web-components/base';
9✔
20
import {
9✔
21
    property,
9✔
22
    query,
9✔
23
} from '@spectrum-web-components/base/src/decorators.js';
9✔
24
import '@spectrum-web-components/underlay/sp-underlay.js';
9✔
25
import { firstFocusableIn } from '@spectrum-web-components/shared/src/first-focusable-in.js';
9✔
26
import { MatchMediaController } from '@spectrum-web-components/reactive-controllers/src/MatchMedia.js';
9✔
27

9✔
28
import modalStyles from '@spectrum-web-components/modal/src/modal.css.js';
9✔
29
import styles from './tray.css.js';
9✔
30

9✔
31
/**
9✔
32
 * @element sp-tray
9✔
33
 *
9✔
34
 * @slot - content to display within the Tray
9✔
35
 *
9✔
36
 * @fires close - Announces that the Tray has been closed.
9✔
37
 */
9✔
38
export class Tray extends SpectrumElement {
9✔
39
    public static override get styles(): CSSResultArray {
9✔
40
        return [modalStyles, styles];
9✔
41
    }
9✔
42

9✔
43
    @property({ type: Boolean, reflect: true })
9✔
44
    public open = false;
9✔
45

9✔
46
    protected prefersMotion = new MatchMediaController(
9✔
47
        this,
9✔
48
        '(prefers-reduced-motion: no-preference)'
9✔
49
    );
9✔
50

9✔
51
    private transitionPromise = Promise.resolve();
9✔
52

9✔
53
    private resolveTransitionPromise = () => {};
9✔
54

9✔
55
    @query('.tray')
9✔
56
    private tray!: HTMLDivElement;
9✔
57

9✔
58
    public override focus(): void {
9✔
59
        const firstFocusable = firstFocusableIn(this);
2✔
60
        if (firstFocusable) {
2✔
61
            firstFocusable.focus();
1✔
62
        } else if (this.children.length === 1) {
1✔
63
            this.tray.focus();
1✔
64
        } else {
1✔
65
            super.focus();
×
66
        }
×
67
    }
2✔
68

9✔
69
    private animating = false;
9✔
70

9✔
71
    public overlayWillCloseCallback(): boolean {
9✔
72
        if (!this.open) return this.animating;
×
73
        this.close();
×
74
        return true;
×
75
    }
×
76

9✔
77
    public close(): void {
9✔
78
        this.open = false;
×
79
        if (!this.prefersMotion.matches) {
×
80
            this.dispatchClosed();
×
81
        }
×
82
    }
×
83

9✔
84
    private dispatchClosed(): void {
9✔
85
        this.dispatchEvent(
×
86
            new Event('close', {
×
87
                bubbles: true,
×
88
            })
×
89
        );
×
90
    }
×
91

9✔
92
    protected handleUnderlayTransitionend(): void {
9✔
93
        if (!this.open) {
×
94
            this.resolveTransitionPromise();
×
95
            this.dispatchClosed();
×
96
        }
×
97
    }
×
98

9✔
99
    protected handleTrayTransitionend(): void {
9✔
100
        if (this.open) {
×
101
            this.resolveTransitionPromise();
×
102
        }
×
103
    }
×
104

9✔
105
    protected override update(changes: PropertyValues<this>): void {
9✔
106
        if (
16✔
107
            changes.has('open') &&
16✔
108
            changes.get('open') !== undefined &&
16✔
109
            this.prefersMotion.matches
7✔
110
        ) {
16✔
111
            this.animating = true;
7✔
112
            this.transitionPromise = new Promise((res) => {
7✔
113
                this.resolveTransitionPromise = () => {
7✔
114
                    this.animating = false;
×
115
                    res();
×
116
                };
×
117
            });
7✔
118
        }
7✔
119
        super.update(changes);
16✔
120
    }
16✔
121

9✔
122
    protected override render(): TemplateResult {
9✔
123
        return html`
16✔
124
            <sp-underlay
16✔
125
                ?open=${this.open}
16✔
126
                @close=${this.close}
16✔
127
                @transitionend=${this.handleUnderlayTransitionend}
16✔
128
            ></sp-underlay>
16✔
129
            <div
16✔
130
                class="tray modal"
16✔
131
                tabindex="-1"
16✔
132
                @transitionend=${this.handleTrayTransitionend}
16✔
133
            >
16✔
134
                <slot></slot>
16✔
135
            </div>
16✔
136
        `;
16✔
137
    }
16✔
138

9✔
139
    /**
9✔
140
     * Bind the open/close transition into the update complete lifecycle so
9✔
141
     * that the overlay system can wait for it to be "visibly ready" before
9✔
142
     * attempting to throw focus into the content contained herein. Not
9✔
143
     * waiting for this can cause small amounts of page scroll to happen
9✔
144
     * while opening the Tray when focusable content is included: e.g. Menu
9✔
145
     * elements whose selected Menu Item is not the first Menu Item.
9✔
146
     */
9✔
147
    protected override async getUpdateComplete(): Promise<boolean> {
9✔
148
        const complete = (await super.getUpdateComplete()) as boolean;
13✔
149
        await this.transitionPromise;
13✔
150
        return complete;
10✔
151
    }
13✔
152
}
9✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc