Conversation
|
Thanks for the PR! 🎉 We've deployed an automatic preview for this PR - you can see your changes here:
Note The build needs to finish before your changes are deployed. |
d5acf16 to
5631193
Compare
| const BACKDROP_DELAY_MS = 800; | ||
| const BACKDROP_FADE_IN_DURATION_MS = 500; | ||
| const BACKDROP_FADE_OUT_DURATION_MS = 500; | ||
| 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 = 500; |
There was a problem hiding this comment.
Values to be discussed with design folks on the Gaudi side- some of these might be redundant if we don't plan on differentiating the values, in which case I can simply the CSS below a bit.
| static get properties() { | ||
| return { | ||
| shown: { type: Boolean }, | ||
| _state: { type: String, reflect: true }, |
There was a problem hiding this comment.
Following a similar pattern to backdrop.js here using a string state
| } | ||
|
|
||
| static get styles() { | ||
| return css` |
There was a problem hiding this comment.
I discussed leveraging some styles from backdrop.js by changing that module to export some styles, similar to how we export tableStyles, but ultimately found that there wasn't all that much overlap aside from the color and opacity. I didn't feel it was worth the indirection- but open to opinions here.
There was a problem hiding this comment.
At some point in the near future we will be replacing the color with a more meaningful CSS variable that they both can use.
| static get styles() { | ||
| return css` | ||
| :host, .backdrop, d2l-loading-spinner { | ||
| width: 0%; |
There was a problem hiding this comment.
A learning point for me- when using transitions, I can't rely on display: none to keep the table interactive while this isn't on, because going from display:none; opacity: 0 to display:block; opacity: 1 doesn't count as a change in opacity, as the display:none version didn't render at all. Bit of a hassle for fade-in components like these.
This approach to change the width instead matches the implementation in backdrop.js.
|
|
||
| d2l-loading-spinner { | ||
| z-index: 999; | ||
| top: 100px; |
There was a problem hiding this comment.
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. 100px was my 'looks fine to me' value, but maybe there's something more clever relative to the size of the viewport or something 😄
| width: 100%; | ||
| height: 100%; |
There was a problem hiding this comment.
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-out ${SPINNER_DELAY_MS}ms; |
There was a problem hiding this comment.
I've biased this implementation towards configurability for now with individual timings for fade in/fade out, but depending on what Gaudi folks think it might not be necessary, then we can define the transition just once on each element.
| @media (prefers-reduced-motion: reduce) { | ||
| * { transition: none} | ||
| } |
There was a problem hiding this comment.
I may need some guidance on these animation preferences before shipping this- I'm not sure exactly what I need to be responsive to
|
|
||
| render() { | ||
| return html` | ||
| <d2l-loading-spinner _state=${this._state} size="100"></d2l-loading-spinner> |
There was a problem hiding this comment.
Spinner size here was chosen arbitrarily based on the example in the daylight docs- may need design guidance on the appropriate static/dynamic size.
5631193 to
41555c8
Compare
| }), | ||
| new Promise(resolve => { | ||
| loadingSpinner.addEventListener('transitionend', resolve, { once: true }); | ||
| loadingSpinner.addEventListener('transitioncancel', resolve, { once: true }); |
There was a problem hiding this comment.
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 transitionend, the promise will never enqueue in that scenario, because after the fade-in gets cancelled the fade-out is never enqueued because we're already 'faded out' in terms of opacity.
This addition receives the cancel from the fade-in animation and clears the loading state accordingly
components/table/table-wrapper.js
Outdated
| render() { | ||
| const slot = html`<slot @slotchange="${this._handleSlotChange}"></slot>`; | ||
| const slot = html` | ||
| <d2l-table-loading-backdrop ?shown=${this.loading}></d2l-table-loading-backdrop> |
There was a problem hiding this comment.
This positioning of the element projects the backdrop over the scroll wrapper
There was a problem hiding this comment.
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 alongside d2l-backdrop. Alternatively enhancing d2l-backdrop for this case, but making this a separate component helps avoid the conditional logic and behaviour since there are a few things d2l-backdrop does that this doesn't.
It could be defined alongside the CollectionMixin since both d2l-table-wrapper and d2l-list extend that, but unfortunately that currently resides outside of components.
There was a problem hiding this comment.
Makes sense- I'll take a pass to generalize and we can figure out the name/location from there.
| :host, .backdrop, d2l-loading-spinner { | ||
| width: 0%; | ||
| height: 0%; | ||
| position: absolute; |
There was a problem hiding this comment.
Is the d2l-table-wrapper the containing block for this? i.e. it is only rendering the backdrop over the table?
There was a problem hiding this comment.
No- the containing block is the scroll wrapper
There was a problem hiding this comment.
But visually yes, it only renders the backdrop over the table and leaves the rest of the page interactive
Downstream ticket
Upstream ticket
We want to add a visual loading state to the table in the event that the data needs to be refreshed. This can occur after filters are applied, sort orders are changed, and possibly in future when we move to a new page.
I took the initial timings and design from two sources:
Since this functionality may be generally useful, I've tentatively moved it into it's own component and listed it in the docs as a related component to the backdrop.
Demo of the Daylight Docs
Recording.2026-02-05.163844.mp4
Demo of the component in practice:
In this video I cover three scenarios:
Recording.2026-02-05.115314.mp4
Alternatives
Alternatively, we can consider updating the backdrop component itself to be able to encompass both scenarios.
A draft of that approach can be found here: #6570