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

adobe / spectrum-web-components / 13935064496

18 Mar 2025 10:56PM UTC coverage: 97.833% (-0.1%) from 97.981%
13935064496

Pull #5095

github

web-flow
Merge c94c4fd27 into 762e236da
Pull Request #5095: feat(accordion,base,theme): initial global system reporting

5301 of 5604 branches covered (94.59%)

Branch coverage included in aggregate %.

107 of 128 new or added lines in 5 files covered. (83.59%)

43 existing lines in 4 files now uncovered.

33624 of 34183 relevant lines covered (98.36%)

703.37 hits per line

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

88.02
/packages/tray/src/Tray.ts
1
/*
9✔
2
Copyright 2020 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;
3✔
79
        if (!this.prefersMotion.matches) {
3!
80
            this.dispatchClosed();
×
81
        }
×
82
    }
3✔
83

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

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

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

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

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