-
Notifications
You must be signed in to change notification settings - Fork 28
feat: Table visual loading state #6552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| import '../colors/colors.js'; | ||
| import { css, html, LitElement } from 'lit'; | ||
|
|
||
| const BACKDROP_DELAY_MS = 800; | ||
| const BACKDROP_FADE_IN_DURATION_MS = 500; | ||
| const BACKDROP_FADE_OUT_DURATION_MS = 200; | ||
| const SPINNER_DELAY_MS = BACKDROP_DELAY_MS + BACKDROP_FADE_IN_DURATION_MS; | ||
| const SPINNER_FADE_IN_DURATION_MS = 500; | ||
| const SPINNER_FADE_OUT_DURATION_MS = 200; | ||
|
|
||
| /** | ||
| * A component for displaying a semi-transparent backdrop and a loading spinner over the containing element | ||
| */ | ||
| class LoadingBackdrop extends LitElement { | ||
|
|
||
| static get properties() { | ||
| return { | ||
| /** | ||
| * Used to control whether the loading backdrop is shown | ||
| * @type {boolean} | ||
| */ | ||
| shown: { type: Boolean }, | ||
| _state: { type: String, reflect: true }, | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following a similar pattern to |
||
| }; | ||
| } | ||
|
|
||
| static get styles() { | ||
| return css` | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I discussed leveraging some styles from
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At some point in the near future we will be replacing the color with a more meaningful CSS variable that they both can use. |
||
| :host, .backdrop, d2l-loading-spinner { | ||
| width: 0%; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A learning point for me- when using transitions, I can't rely on This approach to change the width instead matches the implementation in |
||
| height: 0%; | ||
| position: absolute; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No- the containing block is the scroll wrapper
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But visually yes, it only renders the backdrop over the table and leaves the rest of the page interactive |
||
| } | ||
|
|
||
| .backdrop, d2l-loading-spinner { | ||
| opacity: 0; | ||
| } | ||
|
|
||
| :host { | ||
| z-index: 999; | ||
| top: 0px; | ||
| } | ||
|
|
||
| .backdrop { | ||
| background-color: var(--d2l-color-regolith); | ||
| } | ||
|
|
||
| d2l-loading-spinner { | ||
| top: 100px; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some design input is needed here- I'm not sure exactly how we want to quantify the vertical positioning of the spinner relative to the table. |
||
| } | ||
|
|
||
| :host([_state="showing"]), | ||
| :host([_state="hiding"]), | ||
| d2l-loading-spinner[_state="showing"], | ||
| d2l-loading-spinner[_state="hiding"], | ||
| .backdrop[_state="showing"], | ||
| .backdrop[_state="hiding"] { | ||
| width: 100%; | ||
| height: 100%; | ||
|
Comment on lines
+58
to
+59
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing the width/height here is how we ensure that our components are shown- also, while these are true, the table below is non-interactive (can't highlight, etc), because these render on top. |
||
| } | ||
|
|
||
| d2l-loading-spinner[_state="showing"] { | ||
| opacity: 1; | ||
| transition: opacity ${SPINNER_FADE_IN_DURATION_MS}ms ease-in ${SPINNER_DELAY_MS}ms; | ||
| } | ||
|
|
||
| .backdrop[_state="showing"] { | ||
| opacity: 0.7; | ||
| transition: opacity ${BACKDROP_FADE_IN_DURATION_MS}ms ease-in ${BACKDROP_DELAY_MS}ms; | ||
| } | ||
|
|
||
| d2l-loading-spinner[_state="hiding"] { | ||
| transition: opacity ${SPINNER_FADE_OUT_DURATION_MS}ms ease-out; | ||
| } | ||
|
|
||
| .backdrop[_state="hiding"] { | ||
| transition: opacity ${BACKDROP_FADE_OUT_DURATION_MS}ms ease-out; | ||
| } | ||
|
|
||
| @media (prefers-reduced-motion: reduce) { | ||
| * { transition: none} | ||
| } | ||
|
Comment on lines
+80
to
+82
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I may need some guidance on these animation preferences before shipping this- I'm not sure exactly what I need to be responsive to |
||
| `; | ||
| } | ||
|
|
||
| constructor() { | ||
| super(); | ||
| this.shown = false; | ||
| this._state = null; | ||
| } | ||
|
|
||
| render() { | ||
| return html` | ||
| <div class="backdrop" _state=${this._state}></div> | ||
| <d2l-loading-spinner _state=${this._state}></d2l-loading-spinner> | ||
| `; | ||
| } | ||
|
|
||
| willUpdate(changedProperties) { | ||
| if (changedProperties.has('shown')) { | ||
| if (this.shown) { | ||
| this._state = 'showing'; | ||
| } else if (changedProperties.get('shown') !== undefined) { | ||
| this._state = 'hiding'; | ||
|
|
||
| this._hideAfterFading(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| _hideAfterFading() { | ||
| const backdrop = this.shadowRoot.querySelector('.backdrop'); | ||
| const loadingSpinner = this.shadowRoot.querySelector('d2l-loading-spinner'); | ||
|
|
||
| Promise.all([ | ||
| new Promise(resolve => { | ||
| backdrop.addEventListener('transitionend', resolve, { once: true }); | ||
| backdrop.addEventListener('transitioncancel', resolve, { once: true }); | ||
| }), | ||
| new Promise(resolve => { | ||
| loadingSpinner.addEventListener('transitionend', resolve, { once: true }); | ||
| loadingSpinner.addEventListener('transitioncancel', resolve, { once: true }); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Listening to the transition cancel here deals with the case where the fade-in animation wasn't complete before we started the fade-out. If we just listen for This addition receives the cancel from the fade-in animation and clears the loading state accordingly |
||
| }) | ||
| ]).then(() => { | ||
| this._state = null; | ||
| }); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| customElements.define('d2l-loading-backdrop', LoadingBackdrop); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I foresee us wanting to use this elsewhere, for example in
d2l-list. I'd be inclined to consider making this more general. It might make sense to define this as a different type of backdrop alongsided2l-backdrop. Alternatively enhancingd2l-backdropfor this case, but making this a separate component helps avoid the conditional logic and behaviour since there are a few thingsd2l-backdropdoes that this doesn't.It could be defined alongside the
CollectionMixinsince bothd2l-table-wrapperandd2l-listextend that, but unfortunately that currently resides outside ofcomponents.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense- I'll take a pass to generalize and we can figure out the name/location from there.